{
  "components": {
    "schemas": {
      "ChatMessage": {
        "properties": {
          "filtered_body": {
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "sender_id": {
            "format": "uuid",
            "type": "string"
          },
          "sender_username": {
            "type": [
              "string",
              "null"
            ]
          },
          "sent_at": {
            "format": "date-time",
            "type": "string"
          }
        },
        "required": [
          "id",
          "sender_id",
          "filtered_body",
          "sent_at"
        ],
        "type": "object"
      },
      "RegisterRequest": {
        "properties": {
          "email": {
            "format": "email",
            "type": "string"
          },
          "password": {
            "minLength": 8,
            "type": "string"
          },
          "referral_code": {
            "description": "Optional referral code",
            "type": "string"
          },
          "username": {
            "type": "string"
          }
        },
        "required": [
          "email",
          "password",
          "username"
        ],
        "type": "object"
      },
      "TOTPSetupResponse": {
        "properties": {
          "secret": {
            "type": "string"
          },
          "uri": {
            "type": "string"
          }
        },
        "required": [
          "secret",
          "uri"
        ],
        "type": "object"
      },
      "AuthResponse": {
        "properties": {
          "token": {
            "type": "string"
          },
          "user": {
            "properties": {
              "email": {
                "format": "email",
                "type": "string"
              },
              "email_verified": {
                "type": "boolean"
              },
              "id": {
                "format": "uuid",
                "type": "string"
              },
              "is_admin": {
                "type": "boolean"
              },
              "tier": {
                "type": "string"
              },
              "totp_enabled": {
                "type": "boolean"
              },
              "username": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "email",
              "username",
              "tier",
              "is_admin",
              "email_verified",
              "totp_enabled"
            ],
            "type": "object"
          }
        },
        "required": [
          "token",
          "user"
        ],
        "type": "object"
      },
      "OAuthAppPublic": {
        "description": "Simplified public view of an OAuth app â€” returned by the public lookup endpoint.",
        "properties": {
          "client_id": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "name": {
            "type": "string"
          }
        },
        "required": [
          "name",
          "client_id"
        ],
        "type": "object"
      },
      "OAuthTokenResponse": {
        "properties": {
          "access_token": {
            "type": "string"
          },
          "expires_in": {
            "type": "integer"
          },
          "refresh_token": {
            "type": "string"
          },
          "session_token": {
            "description": "Short-lived session token â€” only present on authorization_code grants",
            "type": "string"
          },
          "session_token_expires_at": {
            "description": "Expiry of the session token â€” only present on authorization_code grants",
            "format": "date-time",
            "type": "string"
          },
          "token_type": {
            "enum": [
              "Bearer"
            ],
            "type": "string"
          }
        },
        "required": [
          "access_token",
          "token_type",
          "expires_in",
          "refresh_token"
        ],
        "type": "object"
      },
      "TOTPEnableResponse": {
        "properties": {
          "message": {
            "type": "string"
          },
          "recovery_codes": {
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "message",
          "recovery_codes"
        ],
        "type": "object"
      },
      "Friend": {
        "properties": {
          "email": {
            "format": "email",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "username": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "username",
          "email"
        ],
        "type": "object"
      },
      "TablePresenceEntry": {
        "properties": {
          "last_seen": {
            "format": "date-time",
            "type": "string"
          },
          "status": {
            "enum": [
              "online",
              "offline"
            ],
            "type": "string"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "user_id",
          "status",
          "last_seen"
        ],
        "type": "object"
      },
      "AuthorizationCodeResponse": {
        "properties": {
          "code": {
            "type": "string"
          },
          "expires_in": {
            "description": "Always 600 seconds",
            "type": "integer"
          },
          "redirect_uri": {
            "type": "string"
          }
        },
        "required": [
          "code",
          "redirect_uri",
          "expires_in"
        ],
        "type": "object"
      },
      "LoginRequest": {
        "properties": {
          "email": {
            "format": "email",
            "type": "string"
          },
          "password": {
            "type": "string"
          },
          "totp_code": {
            "description": "Required if TOTP is enabled on the account",
            "type": "string"
          }
        },
        "required": [
          "email",
          "password"
        ],
        "type": "object"
      },
      "MeResponse": {
        "properties": {
          "user": {
            "properties": {
              "email": {
                "format": "email",
                "type": "string"
              },
              "email_verified": {
                "type": "boolean"
              },
              "id": {
                "format": "uuid",
                "type": "string"
              },
              "points": {
                "type": "integer"
              },
              "referral_code": {
                "type": "string"
              },
              "signup_multiplier": {
                "type": "integer"
              },
              "stats": {
                "properties": {
                  "connected_apps": {
                    "type": "integer"
                  },
                  "direct_referrals": {
                    "type": "integer"
                  },
                  "total_earned": {
                    "type": "integer"
                  },
                  "total_spent": {
                    "type": "integer"
                  }
                },
                "required": [
                  "direct_referrals",
                  "connected_apps",
                  "total_earned",
                  "total_spent"
                ],
                "type": "object"
              },
              "tier": {
                "type": "string"
              },
              "tier_emoji": {
                "type": "string"
              },
              "totp_enabled": {
                "type": "boolean"
              },
              "username": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "email",
              "username",
              "tier",
              "tier_emoji",
              "points",
              "referral_code",
              "signup_multiplier",
              "email_verified",
              "totp_enabled",
              "stats"
            ],
            "type": "object"
          }
        },
        "required": [
          "user"
        ],
        "type": "object"
      },
      "Error": {
        "properties": {
          "error": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ],
        "type": "object"
      },
      "DeployTier": {
        "properties": {
          "ad_reach_multiplier": {
            "description": "Decimal value as string",
            "type": "string"
          },
          "cpu_limit_millicores": {
            "type": "integer"
          },
          "custom_domain_allowed": {
            "type": "boolean"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "memory_limit_mb": {
            "type": "integer"
          },
          "monthly_cost_points": {
            "type": [
              "integer",
              "null"
            ]
          },
          "monthly_cost_sats": {
            "type": [
              "integer",
              "null"
            ]
          },
          "monthly_stipend_points": {
            "type": "integer"
          },
          "name": {
            "type": "string"
          },
          "payment_method": {
            "enum": [
              "buddo_points",
              "bitcoin"
            ],
            "type": "string"
          },
          "slug": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "name",
          "slug",
          "payment_method",
          "memory_limit_mb",
          "cpu_limit_millicores",
          "custom_domain_allowed",
          "monthly_stipend_points",
          "ad_reach_multiplier"
        ],
        "type": "object"
      },
      "FriendshipResponse": {
        "properties": {
          "friendship_id": {
            "format": "uuid",
            "type": "string"
          },
          "status": {
            "enum": [
              "pending",
              "accepted",
              "rejected",
              "removed"
            ],
            "type": "string"
          }
        },
        "required": [
          "friendship_id",
          "status"
        ],
        "type": "object"
      },
      "OperatorAnalytics": {
        "properties": {
          "total_awards": {
            "type": "integer"
          },
          "total_spends": {
            "type": "integer"
          },
          "total_users": {
            "type": "integer"
          },
          "window_days": {
            "type": "integer"
          }
        },
        "required": [
          "total_users",
          "total_spends",
          "total_awards",
          "window_days"
        ],
        "type": "object"
      },
      "Deployment": {
        "properties": {
          "app_id": {
            "format": "uuid",
            "type": "string"
          },
          "billing_status": {
            "type": [
              "string",
              "null"
            ]
          },
          "container_image": {
            "type": "string"
          },
          "container_name": {
            "type": "string"
          },
          "cpu_limit_millicores": {
            "type": "integer"
          },
          "custom_domain": {
            "type": [
              "string",
              "null"
            ]
          },
          "deploy_tier_id": {
            "format": "uuid",
            "type": "string"
          },
          "deployed_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "health_status": {
            "type": [
              "string",
              "null"
            ]
          },
          "host_server": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "inserted_at": {
            "format": "date-time",
            "type": "string"
          },
          "last_health_check": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "memory_limit_mb": {
            "type": "integer"
          },
          "status": {
            "enum": [
              "pending",
              "deploying",
              "running",
              "stopped",
              "destroyed"
            ],
            "type": "string"
          },
          "stopped_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "subdomain": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "app_id",
          "deploy_tier_id",
          "container_name",
          "container_image",
          "subdomain",
          "status",
          "memory_limit_mb",
          "cpu_limit_millicores",
          "inserted_at"
        ],
        "type": "object"
      },
      "PublicOperator": {
        "properties": {
          "app_description": {
            "type": [
              "string",
              "null"
            ]
          },
          "app_name": {
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "inserted_at": {
            "format": "date-time",
            "type": "string"
          },
          "logo_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "website_url": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "app_name",
          "inserted_at"
        ],
        "type": "object"
      },
      "UserSearchResult": {
        "properties": {
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "username": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "username"
        ],
        "type": "object"
      },
      "TokenRequest": {
        "properties": {
          "token": {
            "type": "string"
          }
        },
        "required": [
          "token"
        ],
        "type": "object"
      },
      "UserProfile": {
        "properties": {
          "user": {
            "description": "User profile object",
            "type": "object"
          }
        },
        "required": [
          "user"
        ],
        "type": "object"
      },
      "TransferPointsResult": {
        "properties": {
          "amount_transferred": {
            "type": "integer"
          },
          "points": {
            "type": "integer"
          },
          "success": {
            "type": "boolean"
          }
        },
        "required": [
          "success",
          "points",
          "amount_transferred"
        ],
        "type": "object"
      },
      "ChatChannel": {
        "properties": {
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "ref_id": {
            "type": [
              "string",
              "null"
            ]
          },
          "type": {
            "enum": [
              "lobby",
              "table"
            ],
            "type": "string"
          }
        },
        "required": [
          "id",
          "type"
        ],
        "type": "object"
      },
      "OAuthAppWithSecret": {
        "allOf": [
          {
            "$ref": "#/components/schemas/OAuthApp"
          },
          {
            "properties": {
              "client_secret": {
                "type": "string"
              }
            },
            "required": [
              "client_secret"
            ],
            "type": "object"
          }
        ],
        "description": "OAuth app including client_secret â€” only returned on creation.",
        "type": "object"
      },
      "DeployLog": {
        "properties": {
          "action": {
            "enum": [
              "create",
              "deploy",
              "stop",
              "restart",
              "destroy",
              "suspend",
              "reactivate"
            ],
            "type": "string"
          },
          "details": {
            "type": [
              "object",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "initiated_by": {
            "format": "uuid",
            "type": [
              "string",
              "null"
            ]
          },
          "inserted_at": {
            "format": "date-time",
            "type": "string"
          },
          "status": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "action",
          "status",
          "inserted_at"
        ],
        "type": "object"
      },
      "TokenIntrospection": {
        "properties": {
          "active": {
            "type": "boolean"
          },
          "app_id": {
            "format": "uuid",
            "type": "string"
          },
          "expires_at": {
            "format": "date-time",
            "type": "string"
          },
          "reason": {
            "description": "Present when active is false (e.g. 'expired')",
            "type": "string"
          },
          "scopes": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          }
        },
        "required": [
          "active"
        ],
        "type": "object"
      },
      "ConnectedApp": {
        "properties": {
          "app_description": {
            "type": [
              "string",
              "null"
            ]
          },
          "app_id": {
            "format": "uuid",
            "type": "string"
          },
          "app_name": {
            "type": "string"
          },
          "connected_at": {
            "format": "date-time",
            "type": "string"
          },
          "last_used": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "logo_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "scopes": {
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "app_id",
          "app_name",
          "scopes",
          "connected_at"
        ],
        "type": "object"
      },
      "ModuleStatus": {
        "properties": {
          "completed": {
            "type": [
              "integer",
              "null"
            ]
          },
          "module_number": {
            "type": "integer"
          },
          "repeat_eligible_at": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "enum": [
              "incomplete",
              "completed"
            ],
            "type": "string"
          },
          "total": {
            "type": [
              "integer",
              "null"
            ]
          }
        },
        "required": [
          "status",
          "module_number"
        ],
        "type": "object"
      },
      "HealthResponse": {
        "properties": {
          "status": {
            "type": "string"
          },
          "version": {
            "type": "string"
          }
        },
        "required": [
          "status",
          "version"
        ],
        "type": "object"
      },
      "OperatorApp": {
        "description": "Full operator app details including user count.",
        "properties": {
          "allowed_scopes": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "app_description": {
            "type": [
              "string",
              "null"
            ]
          },
          "app_name": {
            "type": "string"
          },
          "client_id": {
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "inserted_at": {
            "format": "date-time",
            "type": "string"
          },
          "is_approved": {
            "type": "boolean"
          },
          "listed": {
            "type": "boolean"
          },
          "logo_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "redirect_uris": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "total_users": {
            "type": "integer"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          },
          "website_url": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "app_name",
          "client_id",
          "redirect_uris",
          "allowed_scopes",
          "is_approved",
          "listed",
          "total_users",
          "inserted_at",
          "updated_at"
        ],
        "type": "object"
      },
      "ErrorWithMessage": {
        "properties": {
          "error": {
            "type": "string"
          },
          "message": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ],
        "type": "object"
      },
      "CreateDeploymentRequest": {
        "properties": {
          "custom_domain": {
            "description": "Optional custom domain for the deployment",
            "type": "string"
          },
          "env_vars": {
            "additionalProperties": {
              "type": "string"
            },
            "description": "Environment variables (max 50 keys)",
            "maxProperties": 50,
            "type": "object"
          },
          "image": {
            "description": "Container image â€” must start with harbor.buddo.xyz:4443/, docker.io/library/, or ghcr.io/",
            "type": "string"
          },
          "port": {
            "default": 3000,
            "description": "Container port to expose (default 3000)",
            "maximum": 65535,
            "minimum": 1,
            "type": "integer"
          },
          "name": {
            "description": "Name for the deployment (1-32 chars, lowercase alphanumeric and hyphens)",
            "maxLength": 32,
            "minLength": 1,
            "pattern": "^[a-z0-9]([a-z0-9-]*[a-z0-9])?$",
            "type": "string"
          },
          "tier": {
            "description": "Deploy tier slug",
            "type": "string"
          }
        },
        "required": [
          "name",
          "image",
          "tier"
        ],
        "type": "object"
      },
      "PresenceEntry": {
        "properties": {
          "current_game": {
            "type": [
              "string",
              "null"
            ]
          },
          "last_seen": {
            "format": "date-time",
            "type": "string"
          },
          "lobby": {
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "enum": [
              "online",
              "offline"
            ],
            "type": "string"
          }
        },
        "required": [
          "status",
          "last_seen"
        ],
        "type": "object"
      },
      "OAuthError": {
        "description": "OAuth 2.0 error response per RFC 6749",
        "properties": {
          "error": {
            "type": "string"
          },
          "error_description": {
            "type": "string"
          }
        },
        "required": [
          "error"
        ],
        "type": "object"
      },
      "PhoenixError": {
        "description": "Phoenix default error format â€” used by some endpoints.",
        "properties": {
          "errors": {
            "properties": {
              "detail": {
                "type": "string"
              }
            },
            "required": [
              "detail"
            ],
            "type": "object"
          }
        },
        "required": [
          "errors"
        ],
        "type": "object"
      },
      "SpendPointsResult": {
        "properties": {
          "amount_spent": {
            "type": "integer"
          },
          "points": {
            "type": "integer"
          },
          "success": {
            "type": "boolean"
          }
        },
        "required": [
          "success",
          "points",
          "amount_spent"
        ],
        "type": "object"
      },
      "PointsBalance": {
        "properties": {
          "points": {
            "type": "integer"
          }
        },
        "required": [
          "points"
        ],
        "type": "object"
      },
      "AdEvent": {
        "properties": {
          "event": {
            "properties": {
              "campaign_id": {
                "format": "uuid",
                "type": "string"
              },
              "event_type": {
                "enum": [
                  "impression",
                  "click"
                ],
                "type": "string"
              },
              "id": {
                "format": "uuid",
                "type": "string"
              },
              "inserted_at": {
                "format": "date-time",
                "type": "string"
              },
              "payout_rate_snapshot": {
                "type": "number"
              },
              "surface_type": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "campaign_id",
              "event_type",
              "payout_rate_snapshot",
              "surface_type",
              "inserted_at"
            ],
            "type": "object"
          }
        },
        "required": [
          "event"
        ],
        "type": "object"
      },
      "ScopeRequest": {
        "properties": {
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "inserted_at": {
            "format": "date-time",
            "type": "string"
          },
          "requested_scopes": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "status": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "status",
          "requested_scopes",
          "inserted_at"
        ],
        "type": "object"
      },
      "RegisterResponse": {
        "properties": {
          "user": {
            "properties": {
              "email": {
                "format": "email",
                "type": "string"
              },
              "email_verified": {
                "type": "boolean"
              },
              "id": {
                "format": "uuid",
                "type": "string"
              },
              "points": {
                "type": "integer"
              },
              "referral_code": {
                "type": "string"
              },
              "registration_number": {
                "type": "integer"
              },
              "tier": {
                "type": "string"
              },
              "username": {
                "type": "string"
              }
            },
            "required": [
              "id",
              "email",
              "username",
              "tier",
              "points",
              "referral_code",
              "email_verified",
              "registration_number"
            ],
            "type": "object"
          }
        },
        "required": [
          "user"
        ],
        "type": "object"
      },
      "OperatorAppUpdate": {
        "description": "Operator app details returned after update â€” excludes total_users.",
        "properties": {
          "allowed_scopes": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "app_description": {
            "type": [
              "string",
              "null"
            ]
          },
          "app_name": {
            "type": "string"
          },
          "client_id": {
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "inserted_at": {
            "format": "date-time",
            "type": "string"
          },
          "is_approved": {
            "type": "boolean"
          },
          "listed": {
            "type": "boolean"
          },
          "logo_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "redirect_uris": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "updated_at": {
            "format": "date-time",
            "type": "string"
          },
          "website_url": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "app_name",
          "client_id",
          "redirect_uris",
          "allowed_scopes",
          "is_approved",
          "listed",
          "inserted_at",
          "updated_at"
        ],
        "type": "object"
      },
      "PublicOperatorList": {
        "properties": {
          "data": {
            "items": {
              "$ref": "#/components/schemas/PublicOperator"
            },
            "type": "array"
          },
          "page": {
            "type": "integer"
          },
          "page_size": {
            "type": "integer"
          },
          "total": {
            "type": "integer"
          }
        },
        "required": [
          "data",
          "page",
          "page_size",
          "total"
        ],
        "type": "object"
      },
      "SessionStatus": {
        "properties": {
          "is_alive": {
            "type": "boolean"
          },
          "last_heartbeat": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "points_earned": {
            "type": [
              "integer",
              "null"
            ]
          },
          "session_active": {
            "type": "boolean"
          },
          "session_id": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "session_active",
          "session_id",
          "points_earned",
          "last_heartbeat",
          "is_alive"
        ],
        "type": "object"
      },
      "DeploymentStatus": {
        "description": "Lightweight deployment status â€” subset of full Deployment object.",
        "properties": {
          "health_status": {
            "type": [
              "string",
              "null"
            ]
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "last_health_check": {
            "format": "date-time",
            "type": [
              "string",
              "null"
            ]
          },
          "status": {
            "enum": [
              "pending",
              "deploying",
              "running",
              "stopped",
              "destroyed"
            ],
            "type": "string"
          },
          "subdomain": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "status",
          "subdomain"
        ],
        "type": "object"
      },
      "SessionRefreshResponse": {
        "properties": {
          "expires_at": {
            "format": "date-time",
            "type": "string"
          },
          "session_token": {
            "type": "string"
          }
        },
        "required": [
          "session_token",
          "expires_at"
        ],
        "type": "object"
      },
      "SessionEndResult": {
        "properties": {
          "message": {
            "type": "string"
          },
          "session_id": {
            "type": "string"
          }
        },
        "required": [
          "message",
          "session_id"
        ],
        "type": "object"
      },
      "MessageResponse": {
        "properties": {
          "message": {
            "type": "string"
          }
        },
        "required": [
          "message"
        ],
        "type": "object"
      },
      "OAuthApp": {
        "properties": {
          "allowed_scopes": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "app_description": {
            "type": "string"
          },
          "app_name": {
            "type": "string"
          },
          "client_id": {
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "inserted_at": {
            "format": "date-time",
            "type": "string"
          },
          "is_approved": {
            "type": "boolean"
          },
          "logo_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "redirect_uris": {
            "items": {
              "type": "string"
            },
            "type": "array"
          },
          "website_url": {
            "type": [
              "string",
              "null"
            ]
          }
        },
        "required": [
          "id",
          "app_name",
          "client_id",
          "redirect_uris",
          "allowed_scopes",
          "is_approved"
        ],
        "type": "object"
      },
      "PendingFriendRequest": {
        "properties": {
          "friendship_id": {
            "format": "uuid",
            "type": "string"
          },
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "sent_at": {
            "format": "date-time",
            "type": "string"
          },
          "username": {
            "type": "string"
          }
        },
        "required": [
          "id",
          "friendship_id",
          "username",
          "sent_at"
        ],
        "type": "object"
      },
      "LearningPathResponse": {
        "properties": {
          "learning_path": {
            "type": "string"
          },
          "status": {
            "type": "string"
          }
        },
        "required": [
          "status",
          "learning_path"
        ],
        "type": "object"
      },
      "Campaign": {
        "properties": {
          "campaign": {
            "properties": {
              "bitcoin_tier": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "id": {
                "format": "uuid",
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "payout_rate": {
                "type": "number"
              },
              "surface_type": {
                "type": "string"
              },
              "targeting_metadata": {
                "type": [
                  "object",
                  "null"
                ]
              }
            },
            "required": [
              "id",
              "name",
              "surface_type",
              "payout_rate"
            ],
            "type": "object"
          }
        },
        "required": [
          "campaign"
        ],
        "type": "object"
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "bearerFormat": "JWT",
        "description": "JWT token obtained from POST /api/auth/login",
        "scheme": "bearer",
        "type": "http"
      },
      "oauth2": {
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "/api/oauth/authorize",
            "scopes": {
              "app:balance:read": "Read the operator app's point balance",
              "deploy:manage": "Deploy and manage hosted applications",
              "points:award": "Deprecated â€” award is admin-only. Retained for existing token compatibility.",
              "points:read": "Read user point balance",
              "points:spend": "Spend user points (credits operator account)",
              "points:transfer": "Transfer points between users",
              "profile:read": "Read user profile and session information"
            },
            "tokenUrl": "/api/oauth/token",
            "x-pkce-required": true
          }
        },
        "type": "oauth2"
      }
    }
  },
  "info": {
    "description": "OAuth2-protected API for operator applications to manage user profiles, points, sessions, and ads on the Buddo platform.",
    "title": "Buddo External API",
    "version": "2.0.0"
  },
  "openapi": "3.1.0",
  "paths": {
    "/api/social/users/search": {
      "get": {
        "description": "Returns up to 20 matching users. Excludes the current user and blocked users.",
        "operationId": "searchUsers",
        "parameters": [
          {
            "description": "Search query (minimum 2 characters)",
            "in": "query",
            "name": "q",
            "required": true,
            "schema": {
              "minLength": 2,
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "users": {
                      "items": {
                        "$ref": "#/components/schemas/UserSearchResult"
                      },
                      "maxItems": 20,
                      "type": "array"
                    }
                  },
                  "required": [
                    "users"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Search results"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Query too short (minimum 2 characters)"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Search users by username",
        "tags": [
          "Social"
        ]
      }
    },
    "/api/external/points/spend": {
      "post": {
        "operationId": "spendPoints",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "amount": {
                    "minimum": 1,
                    "type": "integer"
                  },
                  "description": {
                    "type": "string"
                  }
                },
                "required": [
                  "amount"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SpendPointsResult"
                }
              }
            },
            "description": "Points spent"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Bad request"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Insufficient balance or app account not found"
          }
        },
        "security": [
          {
            "oauth2": [
              "points:spend"
            ]
          }
        ],
        "summary": "Spend user points, crediting the operator account",
        "tags": [
          "Points"
        ],
        "description": "\n\n**Authentication:** Requires an OAuth access token (Bearer) with the appropriate scope, not a JWT. Use the token returned by POST /api/oauth/token."
      }
    },
    "/api/deploy/apps": {
      "get": {
        "description": "Returns all deployments owned by the authenticated operator. Rate limited to 30 requests per minute.\n\n**Authentication:** Requires an OAuth access token (Bearer), not a JWT. Use the token returned by POST /api/oauth/token.",
        "operationId": "listDeployments",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "deployments": {
                      "items": {
                        "$ref": "#/components/schemas/Deployment"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "deployments"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "List of deployments"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid OAuth token"
          }
        },
        "security": [
          {
            "oauth2": [
              "deploy:manage"
            ]
          }
        ],
        "summary": "List operator's deployments",
        "tags": [
          "Deploy"
        ]
      },
      "post": {
        "description": "Creates a new container deployment on the specified tier. Rate limited to 10 requests per minute.\n\n**Authentication:** Requires an OAuth access token (Bearer), not a JWT. Use the token returned by POST /api/oauth/token.",
        "operationId": "createDeployment",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateDeploymentRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "deployment": {
                      "$ref": "#/components/schemas/Deployment"
                    }
                  },
                  "required": [
                    "deployment"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Deployment created"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid OAuth token"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Tier not found"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Validation failed (invalid name, image, or tier)"
          },
          "429": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Deployment limit reached for this tier/account"
          }
        },
        "security": [
          {
            "oauth2": [
              "deploy:manage"
            ]
          }
        ],
        "summary": "Create a new deployment",
        "tags": [
          "Deploy"
        ]
      }
    },
    "/health": {
      "get": {
        "description": "Returns server health status and API version.",
        "operationId": "healthCheck",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthResponse"
                }
              }
            },
            "description": "Server is healthy"
          }
        },
        "summary": "Health check",
        "tags": [
          "Infrastructure"
        ]
      }
    },
    "/api/oauth/apps/{client_id}": {
      "get": {
        "description": "Returns public app information. No authentication required.",
        "operationId": "getOAuthApp",
        "parameters": [
          {
            "description": "The OAuth app's client_id",
            "in": "path",
            "name": "client_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OAuthAppPublic"
                }
              }
            },
            "description": "Public app info"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "App not found"
          }
        },
        "summary": "Get public app metadata by client_id",
        "tags": [
          "OAuth"
        ]
      }
    },
    "/api/btc-progress/learning-path": {
      "post": {
        "description": "Sets the user's learning path. Cannot be changed after starting modules.",
        "operationId": "setLearningPath",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "path": {
                    "description": "Learning path identifier",
                    "type": "string"
                  }
                },
                "required": [
                  "path"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/LearningPathResponse"
                }
              }
            },
            "description": "Learning path set"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Invalid or missing path"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Cannot change learning path after starting modules"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Set learning path",
        "tags": [
          "Education"
        ]
      }
    },
    "/api/auth/reset-password": {
      "post": {
        "operationId": "resetPassword",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "password": {
                    "minLength": 8,
                    "type": "string"
                  },
                  "token": {
                    "type": "string"
                  }
                },
                "required": [
                  "token",
                  "password"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResponse"
                }
              }
            },
            "description": "Password reset successful"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "$ref": "#/components/schemas/PhoenixError"
                    }
                  ]
                }
              }
            },
            "description": "Invalid or expired token, or missing parameters"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Password too short (minimum 8 characters)"
          }
        },
        "summary": "Reset password using a reset token",
        "tags": [
          "Auth"
        ]
      }
    },
    "/api/social/friends/pending": {
      "get": {
        "operationId": "listPendingFriendRequests",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/PendingFriendRequest"
                  },
                  "type": "array"
                }
              }
            },
            "description": "List of pending friend requests"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List pending friend requests to the current user",
        "tags": [
          "Social"
        ]
      }
    },
    "/api/auth/totp/enable": {
      "post": {
        "description": "Requires a valid TOTP code from the authenticator app. Returns recovery codes on success â€” these should be stored securely by the user.",
        "operationId": "enableTotp",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "code": {
                    "description": "6-digit TOTP code from authenticator app",
                    "type": "string"
                  }
                },
                "required": [
                  "code"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TOTPEnableResponse"
                }
              }
            },
            "description": "TOTP enabled, recovery codes returned"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "TOTP setup not initiated or missing code parameter"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Invalid TOTP code or unauthorized"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Enable TOTP by confirming a valid code",
        "tags": [
          "Auth"
        ]
      }
    },
    "/api/session/refresh": {
      "post": {
        "description": "Validates the current session token, sends a heartbeat, and returns a rotated token. The old token is invalidated atomically. Rate limited to 20 requests per minute per IP. Does not use JWT â€” authenticates via the session_token in the request body.",
        "operationId": "refreshSession",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "session_token": {
                    "description": "The current session token to refresh",
                    "type": "string"
                  }
                },
                "required": [
                  "session_token"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionRefreshResponse"
                }
              }
            },
            "description": "New session token issued"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Missing session_token parameter"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Session expired or token invalid/already consumed"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Session not found (GenServer no longer running)"
          }
        },
        "summary": "Refresh a session token",
        "tags": [
          "Sessions"
        ]
      }
    },
    "/api/external/ads/serve": {
      "get": {
        "operationId": "serveAd",
        "parameters": [
          {
            "description": "The ad surface type to serve",
            "in": "query",
            "name": "surface_type",
            "required": true,
            "schema": {
              "enum": [
                "banner",
                "video",
                "interstitial",
                "native",
                "rewarded"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Campaign"
                }
              }
            },
            "description": "Campaign served"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorWithMessage"
                }
              }
            },
            "description": "Bad request â€” missing or invalid surface_type"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorWithMessage"
                }
              }
            },
            "description": "No campaign available"
          }
        },
        "security": [
          {
            "oauth2": [
              "profile:read"
            ]
          }
        ],
        "summary": "Serve an ad campaign for a given surface type",
        "tags": [
          "Ads"
        ],
        "description": "\n\n**Authentication:** Requires an OAuth access token (Bearer) with the appropriate scope, not a JWT. Use the token returned by POST /api/oauth/token."
      }
    },
    "/api/external/points/transfer": {
      "post": {
        "operationId": "transferPoints",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "amount": {
                    "minimum": 1,
                    "type": "integer"
                  },
                  "description": {
                    "type": "string"
                  },
                  "to_user_id": {
                    "format": "uuid",
                    "type": "string"
                  }
                },
                "required": [
                  "amount",
                  "to_user_id"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TransferPointsResult"
                }
              }
            },
            "description": "Points transferred"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Bad request"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Insufficient balance"
          }
        },
        "security": [
          {
            "oauth2": [
              "points:transfer"
            ]
          }
        ],
        "summary": "Transfer points from the authenticated user to another user",
        "tags": [
          "Points"
        ],
        "description": "\n\n**Authentication:** Requires an OAuth access token (Bearer) with the appropriate scope, not a JWT. Use the token returned by POST /api/oauth/token."
      }
    },
    "/api/auth/login": {
      "post": {
        "description": "Returns a JWT token on success. If the account has TOTP enabled and no totp_code is provided, returns 401 with totp_required: true. Rate limited to 10 requests per minute per IP.",
        "operationId": "loginUser",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LoginRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthResponse"
                }
              }
            },
            "description": "Login successful"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Missing email or password"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "error": {
                      "type": "string"
                    },
                    "totp_required": {
                      "description": "Present and true when TOTP code is needed",
                      "type": "boolean"
                    }
                  },
                  "required": [
                    "error"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Invalid credentials or TOTP required"
          }
        },
        "summary": "Authenticate and receive a JWT token",
        "tags": [
          "Auth"
        ]
      }
    },
    "/api/social/friends/{id}": {
      "delete": {
        "operationId": "removeFriend",
        "parameters": [
          {
            "description": "Friendship ID",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "status": {
                      "enum": [
                        "removed"
                      ],
                      "type": "string"
                    }
                  },
                  "required": [
                    "status"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Friendship removed"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Not authorized to remove this friendship"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Friendship not found"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Remove a friendship",
        "tags": [
          "Social"
        ]
      },
      "put": {
        "operationId": "respondToFriendRequest",
        "parameters": [
          {
            "description": "Friendship ID",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "action": {
                    "enum": [
                      "accept",
                      "reject"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "action"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "status": {
                      "enum": [
                        "accepted",
                        "rejected"
                      ],
                      "type": "string"
                    }
                  },
                  "required": [
                    "status"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Friend request accepted or rejected"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Missing or invalid action"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Not authorized to respond to this request"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Friend request not found"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Accept or reject a friend request",
        "tags": [
          "Social"
        ]
      }
    },
    "/api/btc-progress/{step_id}/complete": {
      "post": {
        "description": "Marks a learning step as completed. Returns reward amount if applicable, or indicates if the step was already completed.",
        "operationId": "completeLearningStep",
        "parameters": [
          {
            "description": "The learning step identifier",
            "in": "path",
            "name": "step_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "reward": {
                      "type": [
                        "integer",
                        "null"
                      ]
                    },
                    "status": {
                      "enum": [
                        "completed",
                        "already_completed"
                      ],
                      "type": "string"
                    },
                    "step_id": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "status",
                    "step_id"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Step completion result"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Learning path not set or step not available"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Step not found"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Complete a learning step",
        "tags": [
          "Education"
        ]
      }
    },
    "/api/social/block": {
      "post": {
        "operationId": "blockUser",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "user_id": {
                    "format": "uuid",
                    "type": "string"
                  }
                },
                "required": [
                  "user_id"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "status": {
                      "enum": [
                        "blocked"
                      ],
                      "type": "string"
                    }
                  },
                  "required": [
                    "status"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "User blocked"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Missing user_id"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "User not found"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "User already blocked"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Block a user",
        "tags": [
          "Social"
        ]
      }
    },
    "/api/btc-progress/module/{module_number}/status": {
      "get": {
        "description": "Returns completion status for a specific learning module.",
        "operationId": "getModuleStatus",
        "parameters": [
          {
            "description": "The module number",
            "in": "path",
            "name": "module_number",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ModuleStatus"
                }
              }
            },
            "description": "Module progress status"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Module not found"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Get module progress",
        "tags": [
          "Education"
        ]
      }
    },
    "/api/auth/register": {
      "post": {
        "description": "Creates a new user. Rate limited to 5 requests per hour per IP.",
        "operationId": "registerUser",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RegisterRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RegisterResponse"
                }
              }
            },
            "description": "User created"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "errors": {
                      "description": "Field-level validation errors",
                      "type": "object"
                    }
                  },
                  "required": [
                    "errors"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Validation errors (duplicate email, weak password, etc.)"
          }
        },
        "summary": "Register a new user account",
        "tags": [
          "Auth"
        ]
      }
    },
    "/api/deploy/apps/{id}/status": {
      "get": {
        "description": "Returns only status and health fields â€” optimized for polling. Rate limited to 30 requests per minute.\n\n**Authentication:** Requires an OAuth access token (Bearer), not a JWT. Use the token returned by POST /api/oauth/token.",
        "operationId": "getDeploymentStatus",
        "parameters": [
          {
            "description": "Deployment ID",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DeploymentStatus"
                }
              }
            },
            "description": "Deployment status"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid OAuth token"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Forbidden â€” deployment belongs to another operator"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Deployment not found"
          }
        },
        "security": [
          {
            "oauth2": [
              "deploy:manage"
            ]
          }
        ],
        "summary": "Lightweight deployment status check",
        "tags": [
          "Deploy"
        ]
      }
    },
    "/api/external/user": {
      "get": {
        "operationId": "getUser",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/UserProfile"
                }
              }
            },
            "description": "User profile"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized"
          }
        },
        "security": [
          {
            "oauth2": [
              "profile:read"
            ]
          }
        ],
        "summary": "Get authenticated user profile",
        "tags": [
          "User"
        ],
        "description": "\n\n**Authentication:** Requires an OAuth access token (Bearer) with the appropriate scope, not a JWT. Use the token returned by POST /api/oauth/token."
      }
    },
    "/api/external/ads/event": {
      "post": {
        "operationId": "recordAdEvent",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "campaign_id": {
                    "format": "uuid",
                    "type": "string"
                  },
                  "event_type": {
                    "enum": [
                      "impression",
                      "click"
                    ],
                    "type": "string"
                  },
                  "surface_type": {
                    "default": "banner",
                    "description": "Ad surface type (defaults to banner)",
                    "type": "string"
                  }
                },
                "required": [
                  "campaign_id",
                  "event_type"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AdEvent"
                }
              }
            },
            "description": "Event recorded"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Bad request"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Campaign not found"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Duplicate event"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Campaign exhausted or validation failed"
          }
        },
        "security": [
          {
            "oauth2": [
              "profile:read"
            ]
          }
        ],
        "summary": "Record an ad impression or click event",
        "tags": [
          "Ads"
        ],
        "description": "\n\n**Authentication:** Requires an OAuth access token (Bearer) with the appropriate scope, not a JWT. Use the token returned by POST /api/oauth/token."
      }
    },
    "/api/public/operators": {
      "get": {
        "description": "Returns a paginated list of approved, publicly listed operator apps. No authentication required.",
        "operationId": "listPublicOperators",
        "parameters": [
          {
            "description": "Page number (default 1)",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "minimum": 1,
              "type": "integer"
            }
          },
          {
            "description": "Items per page (default 20, max 100)",
            "in": "query",
            "name": "page_size",
            "required": false,
            "schema": {
              "default": 20,
              "maximum": 100,
              "minimum": 1,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PublicOperatorList"
                }
              }
            },
            "description": "Paginated list of public operators"
          }
        },
        "summary": "List approved public operators",
        "tags": [
          "Public"
        ]
      }
    },
    "/api/btc-progress/available-modules": {
      "get": {
        "description": "Returns the user's learning path and all available modules.",
        "operationId": "listAvailableModules",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "learning_path": {
                      "type": [
                        "string",
                        "null"
                      ]
                    },
                    "modules": {
                      "items": {
                        "type": "object"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "modules"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Available modules"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List available modules",
        "tags": [
          "Education"
        ]
      }
    },
    "/api/oauth/authorize": {
      "get": {
        "description": "Issues an authorization code for the given client_id. Requires PKCE with S256 method. The code is valid for 600 seconds.",
        "operationId": "authorizeApp",
        "parameters": [
          {
            "description": "The OAuth app's client_id",
            "in": "query",
            "name": "client_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Must be 'code'",
            "in": "query",
            "name": "response_type",
            "required": true,
            "schema": {
              "enum": [
                "code"
              ],
              "type": "string"
            }
          },
          {
            "description": "Must match one of the app's registered redirect_uris",
            "in": "query",
            "name": "redirect_uri",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Opaque value for CSRF protection â€” returned unchanged",
            "in": "query",
            "name": "state",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Space-separated scopes (must be subset of app's allowed_scopes)",
            "in": "query",
            "name": "scope",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "PKCE code challenge (BASE64URL(SHA256(code_verifier)))",
            "in": "query",
            "name": "code_challenge",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Must be 'S256' â€” plain is not supported",
            "in": "query",
            "name": "code_challenge_method",
            "required": true,
            "schema": {
              "enum": [
                "S256"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AuthorizationCodeResponse"
                }
              }
            },
            "description": "Authorization code issued"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Invalid request â€” wrong response_type, invalid client_id, invalid redirect_uri, invalid scopes, or code_challenge_method not S256"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "App is not approved"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "errors": {
                      "type": "object"
                    }
                  },
                  "required": [
                    "errors"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Validation errors"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Request an authorization code",
        "tags": [
          "OAuth"
        ]
      }
    },
    "/api/btc-progress/module/{module_number}/reset": {
      "post": {
        "description": "Resets a completed module so it can be repeated. Only available after a cooldown period.",
        "operationId": "resetModule",
        "parameters": [
          {
            "description": "The module number",
            "in": "path",
            "name": "module_number",
            "required": true,
            "schema": {
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "module_number": {
                      "type": "integer"
                    },
                    "status": {
                      "enum": [
                        "reset"
                      ],
                      "type": "string"
                    }
                  },
                  "required": [
                    "status",
                    "module_number"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Module reset"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Module not completed"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Not eligible for repeat yet"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Reset a completed module",
        "tags": [
          "Education"
        ]
      }
    },
    "/api/auth/me": {
      "get": {
        "operationId": "getCurrentUser",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeResponse"
                }
              }
            },
            "description": "User profile with stats"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Get the authenticated user's full profile",
        "tags": [
          "Auth"
        ]
      }
    },
    "/api/oauth/token": {
      "post": {
        "description": "Supports two grant types: 'authorization_code' (with PKCE code_verifier for public clients or client_secret for confidential clients) and 'refresh_token'. Authorization code grants also return a session_token for lightweight session maintenance.",
        "operationId": "exchangeToken",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "discriminator": {
                  "propertyName": "grant_type"
                },
                "oneOf": [
                  {
                    "properties": {
                      "client_id": {
                        "type": "string"
                      },
                      "client_secret": {
                        "description": "Required for confidential clients (alternative to code_verifier)",
                        "type": "string"
                      },
                      "code": {
                        "description": "The authorization code received from /api/oauth/authorize",
                        "type": "string"
                      },
                      "code_verifier": {
                        "description": "PKCE code verifier â€” required for public clients (no client_secret)",
                        "type": "string"
                      },
                      "grant_type": {
                        "enum": [
                          "authorization_code"
                        ],
                        "type": "string"
                      },
                      "redirect_uri": {
                        "description": "Must match the redirect_uri used in the authorize request",
                        "type": "string"
                      }
                    },
                    "required": [
                      "grant_type",
                      "code",
                      "redirect_uri",
                      "client_id"
                    ],
                    "title": "Authorization Code Grant",
                    "type": "object"
                  },
                  {
                    "properties": {
                      "client_id": {
                        "type": "string"
                      },
                      "client_secret": {
                        "type": "string"
                      },
                      "grant_type": {
                        "enum": [
                          "refresh_token"
                        ],
                        "type": "string"
                      },
                      "refresh_token": {
                        "type": "string"
                      }
                    },
                    "required": [
                      "grant_type",
                      "refresh_token",
                      "client_id",
                      "client_secret"
                    ],
                    "title": "Refresh Token Grant",
                    "type": "object"
                  }
                ]
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OAuthTokenResponse"
                }
              }
            },
            "description": "Token exchange successful"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OAuthError"
                }
              }
            },
            "description": "Invalid request â€” see error and error_description fields for details. Possible error codes: invalid_client, invalid_grant (code expired, already used, invalid redirect_uri, invalid code_verifier), invalid_request (PKCE required)"
          }
        },
        "summary": "Exchange an authorization code or refresh token for access tokens",
        "tags": [
          "OAuth"
        ]
      }
    },
    "/api/oauth/my-apps/{id}/scope-request": {
      "post": {
        "description": "Submits a request to expand the app's allowed scopes. Requires admin approval.\n\n**Manual approval process:** Scope requests are reviewed manually by a Buddo admin — there is no automated approval. Approval times vary and there is no webhook or callback; poll GET /api/oauth/my-apps/{id}/scope-requests to check status. A `pending` status means the request is awaiting review.\n\n**deploy:manage is not auto-approved.** This scope grants full deployment management and requires explicit admin sign-off. Submit the request, then contact Buddo support to expedite review.",
        "operationId": "requestAdditionalScopes",
        "parameters": [
          {
            "description": "The app's internal ID",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "requested_scopes": {
                    "description": "Scopes to add to the app's allowed_scopes",
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  }
                },
                "required": [
                  "requested_scopes"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScopeRequest"
                }
              }
            },
            "description": "Scope request created"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "You do not own this app"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "App not found"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Invalid scopes, already granted, or validation error"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Request additional scopes for an owned app",
        "tags": [
          "OAuth"
        ]
      }
    },
    "/api/oauth/apps": {
      "post": {
        "description": "Creates a new OAuth app. Returns the client_secret — this is the only time it is shown. Rate limited to 3 requests per hour.\n\n**Requires email verification.** This endpoint is behind the `email_verified` pipeline. Your account email must be verified before you can register OAuth apps. If your email is not verified, this endpoint returns 403. To verify your email: call POST /api/auth/send-verification (requires JWT) to receive a verification code, then call POST /api/auth/verify-email with the code. After verification, retry this request with your JWT bearer token.",
        "operationId": "createOAuthApp",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "requested_scopes": {
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  },
                  "app_description": {
                    "type": "string"
                  },
                  "app_name": {
                    "type": "string"
                  },
                  "logo_url": {
                    "type": "string"
                  },
                  "redirect_uris": {
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  },
                  "website_url": {
                    "type": "string"
                  }
                },
                "required": [
                  "app_name",
                  "redirect_uris"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "app": {
                      "$ref": "#/components/schemas/OAuthAppWithSecret"
                    }
                  },
                  "required": [
                    "app"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "App created â€” client_secret included in response (shown only once)"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "errors": {
                      "type": "object"
                    }
                  },
                  "required": [
                    "errors"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Validation errors"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Register a new OAuth app",
        "tags": [
          "OAuth"
        ]
      }
    },
    "/api/auth/totp/verify": {
      "post": {
        "operationId": "verifyTotp",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "code": {
                    "description": "6-digit TOTP code or recovery code",
                    "type": "string"
                  }
                },
                "required": [
                  "code"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResponse"
                }
              }
            },
            "description": "TOTP verified"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "TOTP not enabled or missing code parameter"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Invalid TOTP or recovery code"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Verify a TOTP or recovery code",
        "tags": [
          "Auth"
        ]
      }
    },
    "/api/oauth/my-apps/{id}": {
      "put": {
        "operationId": "updateMyApp",
        "parameters": [
          {
            "description": "The app's internal ID",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "allowed_scopes": {
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  },
                  "app_description": {
                    "type": "string"
                  },
                  "app_name": {
                    "type": "string"
                  },
                  "logo_url": {
                    "type": "string"
                  },
                  "redirect_uris": {
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  },
                  "website_url": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/OAuthApp"
                }
              }
            },
            "description": "App updated"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "You do not own this app"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "App not found"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "errors": {
                      "type": "object"
                    }
                  },
                  "required": [
                    "errors"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Validation errors"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Update an OAuth app owned by the authenticated user",
        "tags": [
          "OAuth"
        ]
      }
    },
    "/.well-known/oauth-protected-resource": {
      "get": {
        "description": "Returns a JSON document describing this resource server's capabilities, supported scopes, and associated authorization server endpoints.",
        "operationId": "oauthProtectedResourceDiscovery",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "description": "RFC 9728 protected resource metadata document",
                  "properties": {
                    "resource": {
                      "description": "The resource server base URL",
                      "type": "string"
                    },
                    "authorization_servers": {
                      "description": "Associated authorization server URLs",
                      "items": {
                        "type": "string"
                      },
                      "type": "array"
                    },
                    "scopes_supported": {
                      "description": "All scopes supported by this resource server",
                      "example": ["points:read", "points:spend", "points:transfer", "points:award", "profile:read", "app:balance:read", "deploy:manage"],
                      "items": {
                        "type": "string"
                      },
                      "type": "array"
                    },
                    "bearer_methods_supported": {
                      "description": "Supported token types",
                      "items": {
                        "type": "string"
                      },
                      "type": "array"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "OAuth Protected Resource metadata"
          }
        },
        "summary": "RFC 9728 OAuth Protected Resource discovery",
        "tags": [
          "Infrastructure"
        ]
      }
    },
    "/api/social/presence/table": {
      "get": {
        "description": "Returns presence status for all users at a specific game table.",
        "operationId": "getTablePresence",
        "parameters": [
          {
            "description": "Game identifier",
            "in": "query",
            "name": "game",
            "required": true,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Table/room reference ID",
            "in": "query",
            "name": "ref_id",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "users": {
                      "items": {
                        "$ref": "#/components/schemas/TablePresenceEntry"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "users"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Table presence list"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Missing game or ref_id parameter"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Get presence for a game table",
        "tags": [
          "Social"
        ]
      }
    },
    "/api/social/block/{user_id}": {
      "delete": {
        "operationId": "unblockUser",
        "parameters": [
          {
            "description": "ID of the user to unblock",
            "in": "path",
            "name": "user_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "status": {
                      "enum": [
                        "unblocked"
                      ],
                      "type": "string"
                    }
                  },
                  "required": [
                    "status"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "User unblocked"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Block record not found"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Unblock a user",
        "tags": [
          "Social"
        ]
      }
    },
    "/api/deploy/apps/{id}/restart": {
      "post": {
        "description": "Restarts the deployment's container. Rate limited to 10 requests per minute.\n\n**Authentication:** Requires an OAuth access token (Bearer), not a JWT. Use the token returned by POST /api/oauth/token.",
        "operationId": "restartDeployment",
        "parameters": [
          {
            "description": "Deployment ID",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "deployment": {
                      "$ref": "#/components/schemas/Deployment"
                    }
                  },
                  "required": [
                    "deployment"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Deployment restarted"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid OAuth token"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Forbidden â€” deployment belongs to another operator"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Deployment not found"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Restart failed (e.g. deployment is destroyed)"
          }
        },
        "security": [
          {
            "oauth2": [
              "deploy:manage"
            ]
          }
        ],
        "summary": "Restart a deployment",
        "tags": [
          "Deploy"
        ]
      }
    },
    "/api/external/session/status": {
      "get": {
        "operationId": "getSessionStatus",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionStatus"
                }
              }
            },
            "description": "Session status"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized"
          }
        },
        "security": [
          {
            "oauth2": [
              "profile:read"
            ]
          }
        ],
        "summary": "Check whether the user has an active session with this app",
        "tags": [
          "Sessions"
        ],
        "description": "\n\n**Authentication:** Requires an OAuth access token (Bearer) with the appropriate scope, not a JWT. Use the token returned by POST /api/oauth/token."
      }
    },
    "/api/operator/analytics": {
      "get": {
        "description": "Returns aggregate analytics for the operator's app over the default 30-day window.\n\n**Authentication:** Requires an OAuth access token (Bearer), not a JWT. Use the token returned by POST /api/oauth/token.",
        "operationId": "getOperatorAnalytics",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "analytics": {
                      "$ref": "#/components/schemas/OperatorAnalytics"
                    }
                  },
                  "required": [
                    "analytics"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Operator analytics"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid OAuth token"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Forbidden â€” not the app owner"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "App not found"
          }
        },
        "security": [
          {
            "oauth2": [
              "app:balance:read"
            ]
          }
        ],
        "summary": "Get operator analytics",
        "tags": [
          "Operator"
        ]
      }
    },
    "/api/auth/totp/setup": {
      "post": {
        "operationId": "setupTotp",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TOTPSetupResponse"
                }
              }
            },
            "description": "TOTP secret and URI for QR code"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "TOTP is already enabled"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Generate a TOTP secret and provisioning URI",
        "tags": [
          "Auth"
        ]
      }
    },
    "/api/social/chat/channels": {
      "post": {
        "description": "Creates a chat channel of the given type, or returns the existing one if it already exists.",
        "operationId": "createChatChannel",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "ref_id": {
                    "description": "Optional reference ID for the channel",
                    "type": "string"
                  },
                  "type": {
                    "enum": [
                      "lobby",
                      "table"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "type"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatChannel"
                }
              }
            },
            "description": "Chat channel created or found"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Missing type parameter"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Create or ensure a chat channel",
        "tags": [
          "Social"
        ]
      }
    },
    "/api/deploy/apps/{id}": {
      "delete": {
        "description": "Permanently destroys a deployment and its container. Rate limited to 10 requests per minute.\n\n**Authentication:** Requires an OAuth access token (Bearer), not a JWT. Use the token returned by POST /api/oauth/token.",
        "operationId": "destroyDeployment",
        "parameters": [
          {
            "description": "Deployment ID",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "id": {
                      "format": "uuid",
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  },
                  "required": [
                    "message",
                    "id"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Deployment destroyed"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid OAuth token"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Forbidden â€” deployment belongs to another operator"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Deployment not found"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Destroy failed"
          }
        },
        "security": [
          {
            "oauth2": [
              "deploy:manage"
            ]
          }
        ],
        "summary": "Destroy a deployment",
        "tags": [
          "Deploy"
        ]
      },
      "get": {
        "description": "Returns full deployment details. Rate limited to 30 requests per minute.\n\n**Authentication:** Requires an OAuth access token (Bearer), not a JWT. Use the token returned by POST /api/oauth/token.",
        "operationId": "getDeployment",
        "parameters": [
          {
            "description": "Deployment ID",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "deployment": {
                      "$ref": "#/components/schemas/Deployment"
                    }
                  },
                  "required": [
                    "deployment"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Deployment details"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid OAuth token"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Forbidden â€” deployment belongs to another operator"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Deployment not found"
          }
        },
        "security": [
          {
            "oauth2": [
              "deploy:manage"
            ]
          }
        ],
        "summary": "Get a single deployment",
        "tags": [
          "Deploy"
        ]
      }
    },
    "/api/auth/forgot-password": {
      "post": {
        "description": "Always returns 200 regardless of whether the email exists, to prevent enumeration. Rate limited to 5 requests per hour per IP.",
        "operationId": "forgotPassword",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "email": {
                    "format": "email",
                    "type": "string"
                  }
                },
                "required": [
                  "email"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResponse"
                }
              }
            },
            "description": "Reset link sent (if email exists)"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Missing email parameter"
          }
        },
        "summary": "Request a password reset link",
        "tags": [
          "Auth"
        ]
      }
    },
    "/api/external/session/end": {
      "post": {
        "operationId": "endSession",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionEndResult"
                }
              }
            },
            "description": "Session ended"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "No active session"
          }
        },
        "security": [
          {
            "oauth2": [
              "profile:read"
            ]
          }
        ],
        "summary": "End the user's active session with this app",
        "tags": [
          "Sessions"
        ],
        "description": "\n\n**Authentication:** Requires an OAuth access token (Bearer) with the appropriate scope, not a JWT. Use the token returned by POST /api/oauth/token."
      }
    },
    "/api/external/points": {
      "get": {
        "operationId": "getPoints",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PointsBalance"
                }
              }
            },
            "description": "Point balance"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized"
          }
        },
        "security": [
          {
            "oauth2": [
              "points:read"
            ]
          }
        ],
        "summary": "Get user point balance",
        "tags": [
          "Points"
        ],
        "description": "\n\n**Authentication:** Requires an OAuth access token (Bearer) with the appropriate scope, not a JWT. Use the token returned by POST /api/oauth/token."
      }
    },
    "/api/oauth/my-apps": {
      "get": {
        "operationId": "listMyApps",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/OAuthApp"
                  },
                  "type": "array"
                }
              }
            },
            "description": "List of owned apps"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List OAuth apps owned by the authenticated user",
        "tags": [
          "OAuth"
        ]
      }
    },
    "/api/oauth/token/verify": {
      "post": {
        "description": "Returns token validity and metadata. Always returns 200 â€” check the 'active' field. No authentication required.",
        "operationId": "verifyToken",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "token": {
                    "description": "The access token to verify",
                    "type": "string"
                  }
                },
                "required": [
                  "token"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TokenIntrospection"
                }
              }
            },
            "description": "Token introspection result (active: true/false)"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Missing token parameter"
          }
        },
        "summary": "Introspect an access token",
        "tags": [
          "OAuth"
        ]
      }
    },
    "/api/deploy/apps/{id}/stop": {
      "post": {
        "description": "Stops the deployment's container. Rate limited to 10 requests per minute.\n\n**Authentication:** Requires an OAuth access token (Bearer), not a JWT. Use the token returned by POST /api/oauth/token.",
        "operationId": "stopDeployment",
        "parameters": [
          {
            "description": "Deployment ID",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "deployment": {
                      "$ref": "#/components/schemas/Deployment"
                    }
                  },
                  "required": [
                    "deployment"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Deployment stopped"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid OAuth token"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Forbidden â€” deployment belongs to another operator"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Deployment not found"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Stop failed (e.g. already stopped or destroyed)"
          }
        },
        "security": [
          {
            "oauth2": [
              "deploy:manage"
            ]
          }
        ],
        "summary": "Stop a running deployment",
        "tags": [
          "Deploy"
        ]
      }
    },
    "/api/social/friends": {
      "get": {
        "operationId": "listFriends",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/Friend"
                  },
                  "type": "array"
                }
              }
            },
            "description": "List of friends"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List current user's friends",
        "tags": [
          "Social"
        ]
      },
      "post": {
        "operationId": "sendFriendRequest",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "friend_id": {
                    "format": "uuid",
                    "type": "string"
                  }
                },
                "required": [
                  "friend_id"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FriendshipResponse"
                }
              }
            },
            "description": "Friend request sent"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Missing friend_id"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Blocked by target user"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "User not found"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Already friends or request already sent"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Send a friend request",
        "tags": [
          "Social"
        ]
      }
    },
    "/api/auth/verify-email": {
      "post": {
        "operationId": "verifyEmail",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TokenRequest"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResponse"
                }
              }
            },
            "description": "Email verified"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "oneOf": [
                    {
                      "$ref": "#/components/schemas/Error"
                    },
                    {
                      "$ref": "#/components/schemas/PhoenixError"
                    }
                  ]
                }
              }
            },
            "description": "Invalid or expired token"
          }
        },
        "summary": "Verify a user's email address with a token",
        "tags": [
          "Auth"
        ]
      }
    },
    "/api/operator/app": {
      "get": {
        "description": "Returns full app details including total user count. Requires the requesting OAuth token to belong to the app owner.\n\n**Authentication:** Requires an OAuth access token (Bearer), not a JWT. Use the token returned by POST /api/oauth/token.",
        "operationId": "getOperatorApp",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "app": {
                      "$ref": "#/components/schemas/OperatorApp"
                    }
                  },
                  "required": [
                    "app"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Operator app details"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid OAuth token"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Forbidden â€” not the app owner"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "App not found"
          }
        },
        "security": [
          {
            "oauth2": [
              "app:balance:read"
            ]
          }
        ],
        "summary": "Get operator's app details",
        "tags": [
          "Operator"
        ]
      },
      "put": {
        "description": "Updates app metadata. All fields are optional. Returns the updated app without total_users.\n\n**Authentication:** Requires an OAuth access token (Bearer), not a JWT. Use the token returned by POST /api/oauth/token.",
        "operationId": "updateOperatorApp",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "app_description": {
                    "type": "string"
                  },
                  "app_name": {
                    "type": "string"
                  },
                  "redirect_uris": {
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  },
                  "website_url": {
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "app": {
                      "$ref": "#/components/schemas/OperatorAppUpdate"
                    }
                  },
                  "required": [
                    "app"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "App updated"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid OAuth token"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Forbidden â€” not the app owner"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "App not found"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Validation failed"
          }
        },
        "security": [
          {
            "oauth2": [
              "app:balance:read"
            ]
          }
        ],
        "summary": "Update operator's app",
        "tags": [
          "Operator"
        ]
      }
    },
    "/api/deploy/apps/{id}/logs": {
      "get": {
        "description": "Returns the audit log of actions performed on a deployment. Rate limited to 30 requests per minute.\n\n**Authentication:** Requires an OAuth access token (Bearer), not a JWT. Use the token returned by POST /api/oauth/token.",
        "operationId": "getDeploymentLogs",
        "parameters": [
          {
            "description": "Deployment ID",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "logs": {
                      "items": {
                        "$ref": "#/components/schemas/DeployLog"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "logs"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Deployment action logs"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid OAuth token"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Forbidden â€” deployment belongs to another operator"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Deployment not found"
          }
        },
        "security": [
          {
            "oauth2": [
              "deploy:manage"
            ]
          }
        ],
        "summary": "Get deployment action logs",
        "tags": [
          "Deploy"
        ]
      }
    },
    "/api/user/connected-apps": {
      "get": {
        "description": "Returns all OAuth apps the authenticated user has authorized.",
        "operationId": "listConnectedApps",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "connected_apps": {
                      "items": {
                        "$ref": "#/components/schemas/ConnectedApp"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "connected_apps"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "List of connected apps"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "List user's connected OAuth apps",
        "tags": [
          "User"
        ]
      }
    },
    "/api/deploy/tiers": {
      "get": {
        "description": "Returns all deployment tiers with pricing and resource limits. Rate limited to 30 requests per minute.\n\n**Authentication:** Requires an OAuth access token (Bearer), not a JWT. Use the token returned by POST /api/oauth/token.",
        "operationId": "listDeployTiers",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "tiers": {
                      "items": {
                        "$ref": "#/components/schemas/DeployTier"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "tiers"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "List of deployment tiers"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid OAuth token"
          }
        },
        "security": [
          {
            "oauth2": [
              "deploy:manage"
            ]
          }
        ],
        "summary": "List available deployment tiers",
        "tags": [
          "Deploy"
        ]
      }
    },
    "/api/auth/send-verification": {
      "post": {
        "operationId": "sendVerificationEmail",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResponse"
                }
              }
            },
            "description": "Verification email sent"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Email already verified"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Resend the email verification link",
        "tags": [
          "Auth"
        ]
      }
    },
    "/api/user/connected-apps/{app_id}": {
      "delete": {
        "description": "Revokes all OAuth tokens for the specified app and removes the connection.",
        "operationId": "revokeConnectedApp",
        "parameters": [
          {
            "description": "The app's ID to revoke",
            "in": "path",
            "name": "app_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MessageResponse"
                }
              }
            },
            "description": "App access revoked"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Connected app not found"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Revoke app access",
        "tags": [
          "User"
        ]
      }
    },
    "/api/external/app/balance": {
      "get": {
        "operationId": "getAppBalance",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PointsBalance"
                }
              }
            },
            "description": "App point balance"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "App account not found"
          }
        },
        "security": [
          {
            "oauth2": [
              "app:balance:read"
            ]
          }
        ],
        "summary": "Get the operator app's earned-point balance",
        "tags": [
          "App"
        ],
        "description": "\n\n**Authentication:** Requires an OAuth access token (Bearer) with the appropriate scope, not a JWT. Use the token returned by POST /api/oauth/token."
      }
    },
    "/api/social/chat/{channel_id}/messages": {
      "get": {
        "description": "Returns messages in reverse chronological order. Supports cursor-based pagination via the 'before' parameter.",
        "operationId": "getChatMessages",
        "parameters": [
          {
            "description": "Chat channel ID",
            "in": "path",
            "name": "channel_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "Number of messages to return (default 50)",
            "in": "query",
            "name": "limit",
            "required": false,
            "schema": {
              "default": 50,
              "type": "integer"
            }
          },
          {
            "description": "Return messages before this timestamp (ISO 8601)",
            "in": "query",
            "name": "before",
            "required": false,
            "schema": {
              "format": "date-time",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "items": {
                    "$ref": "#/components/schemas/ChatMessage"
                  },
                  "type": "array"
                }
              }
            },
            "description": "List of chat messages"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Get messages from a chat channel",
        "tags": [
          "Social"
        ]
      },
      "post": {
        "operationId": "sendChatMessage",
        "parameters": [
          {
            "description": "Chat channel ID",
            "in": "path",
            "name": "channel_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "body": {
                    "maxLength": 1000,
                    "type": "string"
                  }
                },
                "required": [
                  "body"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChatMessage"
                }
              }
            },
            "description": "Message sent"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Missing body"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Invalid message (too long, profanity filter, etc.)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Send a message to a chat channel",
        "tags": [
          "Social"
        ]
      }
    },
    "/api/social/presence": {
      "delete": {
        "description": "Removes the current user's presence record.",
        "operationId": "untrackPresence",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "status": {
                      "enum": [
                        "ok"
                      ],
                      "type": "string"
                    }
                  },
                  "required": [
                    "status"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Presence untracked"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Untrack user presence",
        "tags": [
          "Social"
        ]
      },
      "get": {
        "description": "Returns presence status for the current user's friends. Optionally filter by specific user IDs.",
        "operationId": "getFriendsPresence",
        "parameters": [
          {
            "description": "Comma-separated UUIDs to filter by specific users",
            "in": "query",
            "name": "user_ids",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "additionalProperties": {
                    "$ref": "#/components/schemas/PresenceEntry"
                  },
                  "type": "object"
                }
              }
            },
            "description": "Map of user_id to presence entry"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Get friends' online presence",
        "tags": [
          "Social"
        ]
      },
      "post": {
        "description": "Reports the current user as online, optionally in a specific game or lobby.",
        "operationId": "trackPresence",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "game": {
                    "description": "Current game identifier",
                    "type": "string"
                  },
                  "lobby": {
                    "description": "Current lobby identifier",
                    "type": "string"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": false
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "status": {
                      "enum": [
                        "ok"
                      ],
                      "type": "string"
                    }
                  },
                  "required": [
                    "status"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Presence tracked"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Track user presence",
        "tags": [
          "Social"
        ]
      }
    }
  },
  "servers": [
    {
      "description": "Production",
      "url": "https://api.buddo.xyz"
    },
    {
      "description": "Development",
      "url": "http://localhost:4000"
    }
  ],
  "externalDocs": {
    "description": "Agent onboarding guide",
    "url": "https://docs.buddocloud.com/AGENTS.md"
  }
}