{
  "openapi": "3.1.0",
  "info": {
    "title": "Infinite Assassin Mission Store API",
    "version": "1.0.0 (api_version 1)",
    "description": "Identity + mission storage, discovery and versioning for Infinite Assassin.\n\nAll endpoints are served under the base path `/api/public/v1` (the deployment platform reserves `/api/public/*` for unauthenticated external callers, so `/v1/...` in the original spec maps to `/api/public/v1/...`).\n\nHealth check: `GET https://missionvault.bwlabs.app/api/public/health`.\n\nAuthentication uses `Authorization: Bearer <access-token>`. Tokens are never accepted in query strings.\nMaximum mission_data payload: 1048576 bytes. Supported schema versions: 1."
  },
  "servers": [
    {
      "url": "https://missionvault.bwlabs.app/api/public/v1",
      "description": "Mission Store API v1"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "tags": [
    {
      "name": "Auth"
    },
    {
      "name": "Me"
    },
    {
      "name": "Missions"
    },
    {
      "name": "Discovery"
    },
    {
      "name": "Telemetry"
    },
    {
      "name": "Engagement"
    },
    {
      "name": "Collaboration"
    },
    {
      "name": "Service"
    }
  ],
  "paths": {
    "/auth/register": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Create an account",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegisterRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Account created and signed in",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionResponse"
                }
              }
            }
          },
          "409": {
            "description": "USERNAME_TAKEN or EMAIL_TAKEN",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "INVALID_REQUEST",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/auth/login": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Sign in with email and password",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LoginRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionResponse"
                }
              }
            }
          },
          "401": {
            "description": "INVALID_CREDENTIALS",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/auth/refresh": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Exchange a refresh token for a new session (refresh tokens rotate)",
        "security": [],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RefreshRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenResponse"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/auth/logout": {
      "post": {
        "tags": [
          "Auth"
        ],
        "summary": "Revoke the current session",
        "responses": {
          "204": {
            "description": "Signed out"
          },
          "401": {
            "description": "UNAUTHENTICATED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/me": {
      "get": {
        "tags": [
          "Me"
        ],
        "summary": "Current user profile",
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "tags": [
          "Me"
        ],
        "summary": "Update display name",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMeRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/User"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/me/missions": {
      "get": {
        "tags": [
          "Me"
        ],
        "summary": "My Missions (summaries only, no mission_data)",
        "parameters": [
          {
            "name": "visibility",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "private",
                "public"
              ]
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "updated",
                "newest",
                "title"
              ],
              "default": "updated"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 30
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MissionList"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/missions": {
      "get": {
        "tags": [
          "Discovery"
        ],
        "summary": "Browse public missions",
        "security": [],
        "parameters": [
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "newest",
                "updated",
                "downloads",
                "plays",
                "rating",
                "popular",
                "most_played",
                "most_downloaded"
              ],
              "default": "newest"
            },
            "description": "`downloads` = Most Downloaded (real download counter). `plays`/`most_played`/`popular` = play popularity. `rating` = highest rated."
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 30
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MissionList"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Missions"
        ],
        "summary": "Create a mission",
        "parameters": [
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "High-entropy key (UUID). Repeat requests return the original response."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateMissionRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MissionWriteResult"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "413": {
            "description": "MISSION_TOO_LARGE",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "INVALID_REQUEST / INVALID_MISSION_DATA",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/missions/search": {
      "get": {
        "tags": [
          "Discovery"
        ],
        "summary": "Search public missions by title, description or author username",
        "security": [],
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "schema": {
              "type": "string",
              "maxLength": 200
            }
          },
          {
            "name": "author",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "game_version",
            "in": "query",
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "sort",
            "in": "query",
            "schema": {
              "type": "string",
              "enum": [
                "newest",
                "updated",
                "downloads",
                "plays",
                "rating",
                "popular",
                "most_played",
                "most_downloaded"
              ]
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 30
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MissionList"
                }
              }
            }
          }
        }
      }
    },
    "/missions/{mission_id}": {
      "get": {
        "tags": [
          "Missions"
        ],
        "summary": "Retrieve a mission including mission_data (owner, collaborator, or public)",
        "security": [
          {
            "bearerAuth": []
          },
          {}
        ],
        "parameters": [
          {
            "name": "mission_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "mis_2f7b1f5e-6c1d-4c1e-9f4a-6f2e1c0d3a11"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Mission"
                }
              }
            }
          },
          "404": {
            "description": "MISSION_NOT_FOUND (also returned for other users' private missions)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "tags": [
          "Missions"
        ],
        "summary": "Save mission content (owner or editor collaborator, optimistic concurrency)",
        "description": "Editors may change mission content only. Attempting to set visibility, published state, ownership, deletion state or collaborators as a non-owner returns 403 FORBIDDEN.",
        "parameters": [
          {
            "name": "mission_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "mis_2f7b1f5e-6c1d-4c1e-9f4a-6f2e1c0d3a11"
            }
          },
          {
            "name": "If-Match",
            "in": "header",
            "schema": {
              "type": "string"
            },
            "description": "ETag revision, e.g. \"7\". Alternative to the body revision field."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateMissionRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MissionWriteResult"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "FORBIDDEN — editor attempted an owner-only change",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "MISSION_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Revision conflict",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RevisionConflict"
                }
              }
            }
          },
          "413": {
            "description": "MISSION_TOO_LARGE",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Missions"
        ],
        "summary": "Delete a mission (owner only, soft delete)",
        "parameters": [
          {
            "name": "mission_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "mis_2f7b1f5e-6c1d-4c1e-9f4a-6f2e1c0d3a11"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted"
          },
          "404": {
            "description": "MISSION_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/missions/{mission_id}/visibility": {
      "patch": {
        "tags": [
          "Missions"
        ],
        "summary": "Publish or unpublish (owner only)",
        "parameters": [
          {
            "name": "mission_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "mis_2f7b1f5e-6c1d-4c1e-9f4a-6f2e1c0d3a11"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/VisibilityRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/VisibilityResult"
                }
              }
            }
          },
          "404": {
            "description": "MISSION_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/missions/{mission_id}/plays": {
      "post": {
        "tags": [
          "Telemetry"
        ],
        "summary": "Record a play start",
        "security": [
          {
            "bearerAuth": []
          },
          {}
        ],
        "parameters": [
          {
            "name": "mission_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "mis_2f7b1f5e-6c1d-4c1e-9f4a-6f2e1c0d3a11"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "High-entropy key (UUID). Repeat requests return the original response."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PlayRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Recorded"
          },
          "404": {
            "description": "MISSION_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/missions/{mission_id}/completions": {
      "post": {
        "tags": [
          "Telemetry"
        ],
        "summary": "Record a play completion",
        "security": [
          {
            "bearerAuth": []
          },
          {}
        ],
        "parameters": [
          {
            "name": "mission_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "mis_2f7b1f5e-6c1d-4c1e-9f4a-6f2e1c0d3a11"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "High-entropy key (UUID). Repeat requests return the original response."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CompletionRequest"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "Recorded"
          },
          "404": {
            "description": "MISSION_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/missions/{mission_id}/fork": {
      "post": {
        "tags": [
          "Missions"
        ],
        "deprecated": true,
        "summary": "Removed — mission forking/remixing is no longer supported",
        "description": "Always returns 410 FORKING_DISABLED. Community missions are discover -> download -> play; downloading never grants authoring rights. Collaboration happens on the original mission via /missions/{mission_id}/collaborators.",
        "parameters": [
          {
            "name": "mission_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "mis_2f7b1f5e-6c1d-4c1e-9f4a-6f2e1c0d3a11"
            }
          }
        ],
        "responses": {
          "410": {
            "description": "FORKING_DISABLED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/missions/shared": {
      "get": {
        "tags": [
          "Collaboration"
        ],
        "summary": "Shared With Me — missions where you are an active collaborator (never your own)",
        "description": "Includes private missions shared with you. These never appear in public browse or search.",
        "parameters": [
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 30
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SharedMissionList"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/missions/{mission_id}/collaborators": {
      "get": {
        "tags": [
          "Collaboration"
        ],
        "summary": "List collaborators (owner only)",
        "parameters": [
          {
            "name": "mission_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "mis_2f7b1f5e-6c1d-4c1e-9f4a-6f2e1c0d3a11"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CollaboratorList"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "FORBIDDEN — caller is a collaborator, not the owner",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "MISSION_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "post": {
        "tags": [
          "Collaboration"
        ],
        "summary": "Add a collaborator by username or exact email (owner only)",
        "parameters": [
          {
            "name": "mission_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "mis_2f7b1f5e-6c1d-4c1e-9f4a-6f2e1c0d3a11"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "High-entropy key (UUID). Repeat requests return the original response."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AddCollaboratorRequest"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Collaborator added",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Collaborator"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "FORBIDDEN",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "MISSION_NOT_FOUND or USER_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "COLLABORATOR_EXISTS",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "INVALID_REQUEST",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/missions/{mission_id}/collaborators/{user_id}": {
      "delete": {
        "tags": [
          "Collaboration"
        ],
        "summary": "Remove a collaborator (owner only) — revokes private read/write immediately",
        "parameters": [
          {
            "name": "mission_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "mis_2f7b1f5e-6c1d-4c1e-9f4a-6f2e1c0d3a11"
            }
          },
          {
            "name": "user_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "usr_..."
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Removed"
          },
          "403": {
            "description": "FORBIDDEN",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "MISSION_NOT_FOUND or COLLABORATOR_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/users/search": {
      "get": {
        "tags": [
          "Collaboration"
        ],
        "summary": "Find accounts to invite (authenticated). Never returns email addresses.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 100
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 50,
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserSearchList"
                }
              }
            }
          },
          "401": {
            "description": "UNAUTHENTICATED",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "INVALID_REQUEST",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/missions/{mission_id}/downloads": {
      "post": {
        "tags": [
          "Telemetry"
        ],
        "summary": "Record a download and return the full mission package",
        "description": "A download is distinct from a play. Counted once per (mission, client_id): re-playing an already downloaded local copy must not call this endpoint again.",
        "security": [
          {
            "bearerAuth": []
          },
          {}
        ],
        "parameters": [
          {
            "name": "mission_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "mis_2f7b1f5e-6c1d-4c1e-9f4a-6f2e1c0d3a11"
            }
          },
          {
            "name": "Idempotency-Key",
            "in": "header",
            "required": false,
            "schema": {
              "type": "string",
              "format": "uuid"
            },
            "description": "High-entropy key (UUID). Repeat requests return the original response."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/DownloadRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Mission"
                }
              }
            }
          },
          "404": {
            "description": "MISSION_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/missions/{mission_id}/favourite": {
      "put": {
        "tags": [
          "Engagement"
        ],
        "summary": "Favourite a mission",
        "parameters": [
          {
            "name": "mission_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "mis_2f7b1f5e-6c1d-4c1e-9f4a-6f2e1c0d3a11"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Favourited"
          }
        }
      },
      "delete": {
        "tags": [
          "Engagement"
        ],
        "summary": "Remove a favourite",
        "parameters": [
          {
            "name": "mission_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "mis_2f7b1f5e-6c1d-4c1e-9f4a-6f2e1c0d3a11"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Removed"
          }
        }
      }
    },
    "/missions/{mission_id}/rating": {
      "put": {
        "tags": [
          "Engagement"
        ],
        "summary": "Rate a mission 1-5 (one rating per user)",
        "parameters": [
          {
            "name": "mission_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "mis_2f7b1f5e-6c1d-4c1e-9f4a-6f2e1c0d3a11"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RatingRequest"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RatingResult"
                }
              }
            }
          },
          "404": {
            "description": "MISSION_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "delete": {
        "tags": [
          "Engagement"
        ],
        "summary": "Remove your rating",
        "parameters": [
          {
            "name": "mission_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "example": "mis_2f7b1f5e-6c1d-4c1e-9f4a-6f2e1c0d3a11"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Removed"
          }
        }
      }
    },
    "/users/{username}/missions": {
      "get": {
        "tags": [
          "Discovery"
        ],
        "summary": "Public missions by author (never private)",
        "security": [],
        "parameters": [
          {
            "name": "username",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "limit",
            "in": "query",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 100,
              "default": 30
            }
          },
          {
            "name": "cursor",
            "in": "query",
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthorMissionList"
                }
              }
            }
          },
          "404": {
            "description": "USER_NOT_FOUND",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/config": {
      "get": {
        "tags": [
          "Service"
        ],
        "summary": "Client bootstrap configuration",
        "security": [],
        "responses": {
          "200": {
            "description": "Success",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Config"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "JWT"
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "required": [
          "error"
        ],
        "properties": {
          "error": {
            "type": "object",
            "required": [
              "code",
              "message"
            ],
            "properties": {
              "code": {
                "type": "string",
                "enum": [
                  "INVALID_REQUEST",
                  "UNAUTHENTICATED",
                  "FORBIDDEN",
                  "MISSION_NOT_FOUND",
                  "USER_NOT_FOUND",
                  "MISSION_REVISION_CONFLICT",
                  "MISSION_TOO_LARGE",
                  "INVALID_MISSION_DATA",
                  "USERNAME_TAKEN",
                  "EMAIL_TAKEN",
                  "INVALID_CREDENTIALS",
                  "COLLABORATOR_EXISTS",
                  "COLLABORATOR_NOT_FOUND",
                  "FORKING_DISABLED",
                  "RATE_LIMITED",
                  "METHOD_NOT_ALLOWED",
                  "INTERNAL_ERROR"
                ]
              },
              "message": {
                "type": "string"
              },
              "details": {
                "type": "object",
                "additionalProperties": true
              }
            }
          }
        }
      },
      "User": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "example": "usr_0f0d..."
          },
          "username": {
            "type": "string"
          },
          "display_name": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "Author": {
        "type": "object",
        "properties": {
          "user_id": {
            "type": "string",
            "description": "Canonical field."
          },
          "id": {
            "type": "string",
            "deprecated": true,
            "description": "Alias of user_id."
          },
          "username": {
            "type": "string"
          },
          "display_name": {
            "type": "string"
          }
        }
      },
      "Stats": {
        "type": "object",
        "description": "Canonical statistics block.",
        "properties": {
          "downloads": {
            "type": "integer",
            "description": "Successful Mission Vault downloads. Not incremented by replaying a local copy."
          },
          "plays": {
            "type": "integer",
            "description": "Play sessions started."
          },
          "completions": {
            "type": "integer",
            "description": "Successful completions."
          },
          "favourites": {
            "type": "integer",
            "description": "Users currently favouriting the mission."
          },
          "rating_average": {
            "type": [
              "number",
              "null"
            ]
          },
          "rating_count": {
            "type": "integer"
          },
          "likes": {
            "type": "integer",
            "deprecated": true,
            "description": "Alias of favourites."
          },
          "average_rating": {
            "type": [
              "number",
              "null"
            ],
            "deprecated": true,
            "description": "Alias of rating_average."
          }
        }
      },
      "Counts": {
        "type": "object",
        "description": "Actor counts cached whenever a mission revision is saved.",
        "properties": {
          "targets": {
            "type": "integer"
          },
          "guards": {
            "type": "integer"
          },
          "bodyguards": {
            "type": "integer"
          },
          "civilians": {
            "type": "integer"
          }
        }
      },
      "Viewer": {
        "type": [
          "object",
          "null"
        ],
        "description": "Authenticated viewer state. null for unauthenticated requests.",
        "properties": {
          "is_owner": {
            "type": "boolean"
          },
          "collaboration_role": {
            "type": [
              "string",
              "null"
            ],
            "enum": [
              "editor",
              null
            ]
          },
          "is_favourite": {
            "type": "boolean"
          },
          "my_rating": {
            "type": [
              "integer",
              "null"
            ]
          }
        }
      },
      "Collaborator": {
        "type": "object",
        "properties": {
          "user_id": {
            "type": "string"
          },
          "username": {
            "type": "string"
          },
          "display_name": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": [
              "editor"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CollaboratorList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Collaborator"
            }
          }
        }
      },
      "AddCollaboratorRequest": {
        "type": "object",
        "required": [
          "user"
        ],
        "properties": {
          "user": {
            "type": "string",
            "description": "Username or exact email address of an existing account."
          },
          "role": {
            "type": "string",
            "enum": [
              "editor"
            ],
            "default": "editor"
          }
        }
      },
      "UserSearchList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "user_id": {
                  "type": "string"
                },
                "username": {
                  "type": "string"
                },
                "display_name": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "SharedMissionList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "allOf": [
                {
                  "$ref": "#/components/schemas/MissionSummary"
                },
                {
                  "type": "object",
                  "properties": {
                    "collaboration_role": {
                      "type": "string",
                      "enum": [
                        "editor"
                      ]
                    }
                  }
                }
              ]
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "DownloadRequest": {
        "type": "object",
        "required": [
          "client_id"
        ],
        "properties": {
          "client_id": {
            "type": "string",
            "minLength": 8,
            "maxLength": 128,
            "description": "Stable per-installation identifier. Downloads are counted once per (mission, client_id)."
          }
        }
      },
      "RevisionConflict": {
        "type": "object",
        "properties": {
          "error": {
            "type": "string",
            "enum": [
              "revision_conflict"
            ]
          },
          "message": {
            "type": "string"
          },
          "expected_revision": {
            "type": "integer"
          },
          "current_revision": {
            "type": "integer"
          }
        }
      },
      "MissionSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "visibility": {
            "type": "string",
            "enum": [
              "private",
              "public"
            ]
          },
          "revision": {
            "type": "integer"
          },
          "game_version": {
            "type": "string"
          },
          "minimum_game_version": {
            "type": "string"
          },
          "schema_version": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "published_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "published": {
            "type": "boolean"
          },
          "counts": {
            "$ref": "#/components/schemas/Counts"
          },
          "stats": {
            "$ref": "#/components/schemas/Stats"
          },
          "viewer": {
            "$ref": "#/components/schemas/Viewer"
          },
          "author": {
            "$ref": "#/components/schemas/Author"
          },
          "preview": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/MissionPreview"
              },
              {
                "type": "null"
              }
            ],
            "description": "Canonical preview representation. Read-only projection of mission_data._editor_preview.screenshot_jpeg_base64. Explicitly null when the mission has no authored screenshot — the client should then show its fallback artwork."
          }
        }
      },
      "MissionPreview": {
        "type": "object",
        "properties": {
          "screenshot_jpeg_base64": {
            "type": "string",
            "description": "Base64-encoded JPEG (no data URL prefix), at most 524288 characters. Projected from mission_data._editor_preview.screenshot_jpeg_base64."
          }
        }
      },
      "Mission": {
        "allOf": [
          {
            "$ref": "#/components/schemas/MissionSummary"
          },
          {
            "type": "object",
            "properties": {
              "owner_id": {
                "type": "string"
              },
              "mission_data": {
                "type": "object",
                "additionalProperties": true,
                "description": "Opaque Infinite Assassin mission JSON."
              }
            }
          }
        ]
      },
      "MissionList": {
        "type": "object",
        "properties": {
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MissionSummary"
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "AuthorMissionList": {
        "type": "object",
        "properties": {
          "author": {
            "$ref": "#/components/schemas/Author"
          },
          "items": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/MissionSummary"
            }
          },
          "next_cursor": {
            "type": [
              "string",
              "null"
            ]
          }
        }
      },
      "RegisterRequest": {
        "type": "object",
        "required": [
          "email",
          "username",
          "password"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          },
          "username": {
            "type": "string",
            "pattern": "^[A-Za-z0-9_]{3,24}$"
          },
          "password": {
            "type": "string",
            "minLength": 8
          },
          "display_name": {
            "type": "string",
            "maxLength": 64
          }
        }
      },
      "LoginRequest": {
        "type": "object",
        "required": [
          "email",
          "password"
        ],
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          },
          "password": {
            "type": "string"
          }
        }
      },
      "RefreshRequest": {
        "type": "object",
        "required": [
          "refresh_token"
        ],
        "properties": {
          "refresh_token": {
            "type": "string"
          }
        }
      },
      "UpdateMeRequest": {
        "type": "object",
        "required": [
          "display_name"
        ],
        "properties": {
          "display_name": {
            "type": "string",
            "maxLength": 64
          }
        }
      },
      "TokenResponse": {
        "type": "object",
        "properties": {
          "access_token": {
            "type": "string"
          },
          "refresh_token": {
            "type": "string"
          },
          "token_type": {
            "type": "string",
            "example": "Bearer"
          },
          "expires_in": {
            "type": "integer",
            "example": 3600
          }
        }
      },
      "SessionResponse": {
        "allOf": [
          {
            "type": "object",
            "properties": {
              "user": {
                "$ref": "#/components/schemas/User"
              }
            }
          },
          {
            "$ref": "#/components/schemas/TokenResponse"
          }
        ]
      },
      "CreateMissionRequest": {
        "type": "object",
        "required": [
          "title",
          "game_version",
          "schema_version",
          "mission_data"
        ],
        "properties": {
          "title": {
            "type": "string",
            "maxLength": 120
          },
          "description": {
            "type": "string",
            "maxLength": 4000
          },
          "visibility": {
            "type": "string",
            "enum": [
              "private",
              "public"
            ],
            "default": "private"
          },
          "game_version": {
            "type": "string",
            "example": "0.4.0"
          },
          "minimum_game_version": {
            "type": "string",
            "example": "0.4.0"
          },
          "schema_version": {
            "type": "integer",
            "enum": [
              1
            ]
          },
          "mission_data": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "UpdateMissionRequest": {
        "type": "object",
        "required": [
          "revision"
        ],
        "properties": {
          "revision": {
            "type": "integer",
            "description": "Must equal the server revision or the API returns 409."
          },
          "title": {
            "type": "string",
            "maxLength": 120
          },
          "description": {
            "type": "string",
            "maxLength": 4000
          },
          "visibility": {
            "type": "string",
            "enum": [
              "private",
              "public"
            ]
          },
          "game_version": {
            "type": "string"
          },
          "minimum_game_version": {
            "type": "string"
          },
          "schema_version": {
            "type": "integer"
          },
          "mission_data": {
            "type": "object",
            "additionalProperties": true
          }
        }
      },
      "MissionWriteResult": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "revision": {
            "type": "integer"
          },
          "visibility": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "published_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          }
        }
      },
      "VisibilityRequest": {
        "type": "object",
        "required": [
          "visibility"
        ],
        "properties": {
          "visibility": {
            "type": "string",
            "enum": [
              "private",
              "public"
            ]
          }
        }
      },
      "VisibilityResult": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "visibility": {
            "type": "string"
          },
          "published_at": {
            "type": [
              "string",
              "null"
            ],
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "revision": {
            "type": "integer"
          }
        }
      },
      "PlayRequest": {
        "type": "object",
        "required": [
          "session_id"
        ],
        "properties": {
          "session_id": {
            "type": "string",
            "format": "uuid"
          }
        }
      },
      "CompletionRequest": {
        "type": "object",
        "required": [
          "session_id",
          "outcome"
        ],
        "properties": {
          "session_id": {
            "type": "string",
            "format": "uuid"
          },
          "outcome": {
            "type": "string",
            "enum": [
              "success",
              "failure",
              "abandoned"
            ]
          }
        }
      },
      "ForkResult": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "revision": {
            "type": "integer"
          },
          "visibility": {
            "type": "string"
          },
          "forked_from": {
            "type": [
              "string",
              "null"
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "RatingRequest": {
        "type": "object",
        "required": [
          "rating"
        ],
        "properties": {
          "rating": {
            "type": "integer",
            "minimum": 1,
            "maximum": 5
          }
        }
      },
      "RatingResult": {
        "type": "object",
        "properties": {
          "rating": {
            "type": "integer"
          },
          "rating_count": {
            "type": "integer"
          },
          "average_rating": {
            "type": [
              "number",
              "null"
            ]
          }
        }
      },
      "Config": {
        "type": "object",
        "properties": {
          "api_version": {
            "type": "integer"
          },
          "minimum_game_version": {
            "type": "string"
          },
          "current_game_version": {
            "type": "string"
          },
          "maximum_mission_bytes": {
            "type": "integer"
          },
          "maximum_json_depth": {
            "type": "integer"
          },
          "maximum_string_length": {
            "type": "integer"
          },
          "supported_schema_versions": {
            "type": "array",
            "items": {
              "type": "integer"
            }
          },
          "visibilities": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "list_sorts": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "default_page_limit": {
            "type": "integer"
          },
          "maximum_page_limit": {
            "type": "integer"
          }
        }
      }
    }
  }
}