{
  "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"
          },
          "state": {
            "description": "Echoed back unchanged if state was provided in the authorize request. Use to verify CSRF protection.",
            "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": {
        "description": "Standard error response. The live API returns a nested error object.",
        "properties": {
          "error": {
            "$ref": "#/components/schemas/NestedErrorBody"
          }
        },
        "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": {
            "description": "Application version string",
            "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. Available tiers: \"free\" (512MB RAM, 0.5 CPU, 1 deployment max) and \"basic\" (1GB RAM, 1 CPU, 3 deployments max).",
            "type": "string",
            "enum": [
              "free",
              "basic"
            ]
          }
        },
        "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": "boolean",
                "nullable": true
              },
              "id": {
                "format": "uuid",
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "payout_rate": {
                "type": "number"
              },
              "surface_type": {
                "type": "string"
              },
              "targeting_metadata": {
                "type": [
                  "object",
                  "null"
                ]
              },
              "status": {
                "type": "string",
                "enum": [
                  "active",
                  "paused",
                  "exhausted"
                ]
              },
              "budget": {
                "type": "integer",
                "description": "Campaign budget in Buddo points"
              },
              "spent": {
                "type": "integer",
                "description": "Total points spent so far"
              },
              "starts_at": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              },
              "ends_at": {
                "type": "string",
                "format": "date-time",
                "nullable": true
              },
              "inserted_at": {
                "type": "string",
                "format": "date-time"
              },
              "updated_at": {
                "type": "string",
                "format": "date-time"
              }
            },
            "required": [
              "id",
              "name",
              "surface_type",
              "payout_rate"
            ],
            "type": "object"
          }
        },
        "required": [
          "campaign"
        ],
        "type": "object"
      },
      "CampaignAnalytics": {
        "properties": {
          "campaign_id": {
            "format": "uuid",
            "type": "string"
          },
          "campaign_name": {
            "type": "string"
          },
          "summary": {
            "properties": {
              "total_impressions": {
                "type": "integer"
              },
              "total_clicks": {
                "type": "integer"
              },
              "total_spend": {
                "type": "integer"
              },
              "ctr": {
                "description": "Click-through rate as a percentage",
                "type": "number"
              }
            },
            "required": [
              "total_impressions",
              "total_clicks",
              "total_spend",
              "ctr"
            ],
            "type": "object"
          },
          "daily": {
            "items": {
              "properties": {
                "date": {
                  "format": "date",
                  "type": "string"
                },
                "impressions": {
                  "type": "integer"
                },
                "clicks": {
                  "type": "integer"
                },
                "spend": {
                  "type": "integer"
                }
              },
              "required": [
                "date",
                "impressions",
                "clicks",
                "spend"
              ],
              "type": "object"
            },
            "type": "array"
          }
        },
        "required": [
          "campaign_id",
          "campaign_name",
          "summary",
          "daily"
        ],
        "type": "object"
      },
      "Avatar": {
        "description": "A user's avatar â€” lazy-created on first access.",
        "properties": {
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "user_id": {
            "format": "uuid",
            "type": "string"
          },
          "display_name": {
            "description": "Optional display name for the avatar (max 20 characters)",
            "maxLength": 20,
            "type": [
              "string",
              "null"
            ]
          },
          "appearance": {
            "description": "Free-form appearance configuration object",
            "type": "object"
          },
          "equipped_cosmetics": {
            "description": "List of equipped cosmetic item IDs",
            "items": {
              "type": "string"
            },
            "type": "array"
          }
        },
        "required": [
          "id",
          "user_id",
          "equipped_cosmetics"
        ],
        "type": "object"
      },
      "CosmeticItem": {
        "description": "A cosmetic item available in the catalogue.",
        "properties": {
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": [
              "string",
              "null"
            ]
          },
          "category": {
            "enum": [
              "hat",
              "hair",
              "top",
              "bottom",
              "shoes",
              "accessory",
              "background",
              "frame",
              "emote"
            ],
            "type": "string"
          },
          "rarity": {
            "enum": [
              "common",
              "uncommon",
              "rare",
              "legendary"
            ],
            "type": "string"
          },
          "price_points": {
            "description": "Cost in Buddo points",
            "type": "integer"
          },
          "asset_url": {
            "type": [
              "string",
              "null"
            ]
          },
          "available": {
            "description": "Whether the item is currently available for purchase",
            "type": "boolean"
          }
        },
        "required": [
          "id",
          "name",
          "category",
          "rarity",
          "price_points",
          "available"
        ],
        "type": "object"
      },
      "UserCosmetic": {
        "description": "A cosmetic item owned by a user.",
        "properties": {
          "id": {
            "format": "uuid",
            "type": "string"
          },
          "cosmetic_item_id": {
            "format": "uuid",
            "type": "string"
          },
          "acquired_at": {
            "format": "date-time",
            "type": "string"
          },
          "acquired_via": {
            "enum": [
              "purchase",
              "gift",
              "achievement",
              "promotion"
            ],
            "type": "string"
          },
          "item": {
            "description": "Summary of the cosmetic item",
            "properties": {
              "id": {
                "format": "uuid",
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "category": {
                "type": "string"
              },
              "rarity": {
                "type": "string"
              },
              "asset_url": {
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "required": [
              "id",
              "name",
              "category",
              "rarity"
            ],
            "type": "object"
          }
        },
        "required": [
          "id",
          "cosmetic_item_id",
          "acquired_at",
          "acquired_via"
        ],
        "type": "object"
      },
      "AudienceSegment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "game_type": {
            "type": "string",
            "nullable": true
          },
          "play_tier": {
            "type": "string",
            "nullable": true
          },
          "geography": {
            "type": "string",
            "nullable": true
          },
          "metadata": {
            "type": "object",
            "nullable": true
          },
          "inserted_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AdRate": {
        "type": "object",
        "properties": {
          "surface_type": {
            "type": "string"
          },
          "base_rate": {
            "type": "integer"
          },
          "demand_multiplier": {
            "type": "number",
            "format": "float"
          },
          "popularity_score": {
            "type": "number",
            "format": "float"
          },
          "effective_rate": {
            "type": "integer",
            "description": "Actual current rate in Buddo points per impression"
          },
          "floor_price": {
            "type": "integer",
            "example": 1
          },
          "ceiling_price": {
            "type": "integer",
            "description": "base_rate * 10"
          }
        }
      },
      "PlacementPricingConfig": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "ad_placement_id": {
            "type": "string"
          },
          "base_rate": {
            "type": "integer"
          },
          "demand_multiplier": {
            "type": "number",
            "format": "float"
          },
          "min_rate": {
            "type": "integer"
          },
          "max_rate": {
            "type": "integer"
          },
          "effective_rate": {
            "type": "integer"
          },
          "effective_from": {
            "type": "string",
            "format": "date-time"
          },
          "effective_until": {
            "type": "string",
            "format": "date-time",
            "nullable": true
          },
          "inserted_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AdPackage": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "discount_percentage": {
            "type": "integer"
          },
          "min_surfaces": {
            "type": "integer"
          },
          "min_impressions": {
            "type": "integer"
          },
          "is_active": {
            "type": "boolean"
          },
          "inserted_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "AdPackagePurchase": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "ad_package_id": {
            "type": "string",
            "format": "uuid"
          },
          "operator_id": {
            "type": "string",
            "format": "uuid"
          },
          "campaign_ids": {
            "type": "array",
            "items": {
              "type": "string",
              "format": "uuid"
            }
          },
          "surfaces": {
            "type": "array",
            "items": {
              "type": "object"
            }
          },
          "subtotal": {
            "type": "integer"
          },
          "discount_amount": {
            "type": "integer"
          },
          "rake_amount": {
            "type": "integer"
          },
          "total_charged": {
            "type": "integer"
          },
          "status": {
            "type": "string"
          },
          "inserted_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CampaignSummary": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "name": {
            "type": "string"
          },
          "surface_type": {
            "type": "string"
          },
          "budget": {
            "type": "integer"
          },
          "payout_rate": {
            "type": "integer"
          },
          "status": {
            "type": "string"
          },
          "inserted_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "CampaignPlacement": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "campaign_id": {
            "type": "string",
            "format": "uuid"
          },
          "ad_placement_id": {
            "type": "string",
            "format": "uuid"
          },
          "allocated_budget": {
            "type": "integer"
          },
          "impressions_delivered": {
            "type": "integer"
          },
          "impressions_target": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "active",
              "paused",
              "depleted"
            ]
          },
          "inserted_at": {
            "type": "string",
            "format": "date-time"
          },
          "updated_at": {
            "type": "string",
            "format": "date-time"
          },
          "segments": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/PlacementSegment"
            }
          }
        }
      },
      "PlacementSegment": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "format": "uuid"
          },
          "campaign_placement_id": {
            "type": "string",
            "format": "uuid"
          },
          "segment_type": {
            "type": "string"
          },
          "segment_value": {
            "type": "string"
          },
          "match_mode": {
            "type": "string",
            "enum": [
              "exact",
              "prefix",
              "any"
            ]
          },
          "inserted_at": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "NestedErrorBody": {
        "description": "Nested error object returned by the live API",
        "properties": {
          "code": {
            "type": "string"
          },
          "message": {
            "type": "string"
          },
          "details": {
            "type": "object"
          }
        },
        "required": [
          "code",
          "message"
        ],
        "type": "object"
      }
    },
    "securitySchemes": {
      "bearerAuth": {
        "bearerFormat": "JWT",
        "description": "JWT token obtained from POST /api/auth/login",
        "scheme": "bearer",
        "type": "http"
      },
      "internalSecret": {
        "description": "Internal API secret passed via the x-internal-secret header. Used for platform-level admin operations not accessible to external operators.",
        "in": "header",
        "name": "x-internal-secret",
        "type": "apiKey"
      },
      "oauth2": {
        "flows": {
          "authorizationCode": {
            "authorizationUrl": "/api/oauth/authorize",
            "scopes": {
              "app:balance:read": "Read the operator app's point balance",
              "campaign:write": "Create and manage ad campaigns at /api/external/campaigns/*. Requires admin approval.",
              "campaigns:manage": "Manage operator ad campaigns via Ad Marketplace v2 (/api/v1/ads/*). Controls pause/resume/analytics.",
              "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"
      },
      "internalAuth": {
        "type": "apiKey",
        "in": "header",
        "name": "x-internal-secret"
      }
    }
  },
  "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": "3.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"
            }
          },
          {
            "description": "Optional targeting: game type context (e.g. slots, bit_battle)",
            "in": "query",
            "name": "game_type",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Optional targeting: play tier context (e.g. buddo, bitcoin)",
            "in": "query",
            "name": "play_tier",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Optional targeting: locale context (e.g. en-IE, en-GB)",
            "in": "query",
            "name": "locale",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Optional targeting: user cohort context (e.g. new_user, high_roller)",
            "in": "query",
            "name": "user_cohort",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "campaign": {
                      "$ref": "#/components/schemas/Campaign"
                    },
                    "impression_token": {
                      "type": "string",
                      "description": "Single-use fraud-prevention token. Pass this as impression_token when calling POST /api/external/ads/event. Required - omitting it returns 422 missing_impression_token."
                    }
                  },
                  "required": [
                    "campaign",
                    "impression_token"
                  ]
                }
              }
            },
            "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"
                  },
                  "impression_token": {
                    "type": "string",
                    "description": "The impression_token from GET /api/external/ads/serve. Required for fraud prevention."
                  }
                },
                "required": [
                  "campaign_id",
                  "event_type",
                  "impression_token"
                ],
                "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": {
                  "app_description": {
                    "type": "string"
                  },
                  "app_name": {
                    "type": "string"
                  },
                  "logo_url": {
                    "type": "string"
                  },
                  "redirect_uris": {
                    "items": {
                      "type": "string"
                    },
                    "type": "array"
                  },
                  "website_url": {
                    "type": "string"
                  },
                  "scopes": {
                    "items": {
                      "type": "string"
                    },
                    "type": "array",
                    "description": "Scopes to request for this app. Use scopes in the request body (not allowed_scopes)."
                  }
                },
                "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"
        ]
      }
    },
    "/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/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"
        ]
      }
    },
    "/api/social/avatar": {
      "get": {
        "description": "Returns the authenticated user's avatar. Creates one automatically if it does not yet exist.",
        "operationId": "getMyAvatar",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Avatar"
                }
              }
            },
            "description": "Avatar object"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Get the current user's avatar",
        "tags": [
          "Social"
        ]
      },
      "put": {
        "description": "Updates the authenticated user's avatar display_name and/or appearance. All fields are optional.",
        "operationId": "updateMyAvatar",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "display_name": {
                    "description": "Optional display name (max 20 characters)",
                    "maxLength": 20,
                    "type": "string"
                  },
                  "appearance": {
                    "description": "Free-form appearance configuration object",
                    "type": "object"
                  }
                },
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Avatar"
                }
              }
            },
            "description": "Updated avatar"
          },
          "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": "Validation failed (e.g. display_name too long)"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Update avatar appearance or display name",
        "tags": [
          "Social"
        ]
      }
    },
    "/api/social/avatar/equip": {
      "put": {
        "description": "Equips or unequips a cosmetic item on the authenticated user's avatar. Pass `action: \"unequip\"` to remove an equipped item.",
        "operationId": "equipCosmetic",
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "properties": {
                  "cosmetic_item_id": {
                    "description": "UUID of the cosmetic item to equip or unequip",
                    "format": "uuid",
                    "type": "string"
                  },
                  "action": {
                    "description": "Omit (or any value other than 'unequip') to equip; pass 'unequip' to remove",
                    "enum": [
                      "unequip"
                    ],
                    "type": "string"
                  }
                },
                "required": [
                  "cosmetic_item_id"
                ],
                "type": "object"
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Avatar"
                }
              }
            },
            "description": "Updated avatar with new equipped cosmetics"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "cosmetic_item_id is required"
          },
          "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": "Cosmetic not owned by the user"
          },
          "422": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Operation failed"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Equip or unequip a cosmetic item",
        "tags": [
          "Social"
        ]
      }
    },
    "/api/social/avatar/{user_id}": {
      "get": {
        "description": "Returns the public avatar for any user by their user ID.",
        "operationId": "getPublicAvatar",
        "parameters": [
          {
            "description": "UUID of the user whose avatar to retrieve",
            "in": "path",
            "name": "user_id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Avatar"
                }
              }
            },
            "description": "Public avatar object"
          },
          "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": "Avatar not found"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Get a user's public avatar",
        "tags": [
          "Social"
        ]
      }
    },
    "/api/social/cosmetics": {
      "get": {
        "description": "Returns the full cosmetic catalogue. Supports optional filtering by category and rarity. No authentication required.",
        "operationId": "listCosmetics",
        "parameters": [
          {
            "description": "Filter by category",
            "in": "query",
            "name": "category",
            "required": false,
            "schema": {
              "enum": [
                "hat",
                "hair",
                "top",
                "bottom",
                "shoes",
                "accessory",
                "background",
                "frame",
                "emote"
              ],
              "type": "string"
            }
          },
          {
            "description": "Filter by rarity",
            "in": "query",
            "name": "rarity",
            "required": false,
            "schema": {
              "enum": [
                "common",
                "uncommon",
                "rare",
                "legendary"
              ],
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "items": {
                      "items": {
                        "$ref": "#/components/schemas/CosmeticItem"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "items"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Catalogue items"
          }
        },
        "summary": "Browse the cosmetic catalogue",
        "tags": [
          "Social"
        ]
      }
    },
    "/api/social/cosmetics/{id}/purchase": {
      "post": {
        "description": "Purchases a cosmetic item using the authenticated user's Buddo points.",
        "operationId": "purchaseCosmetic",
        "parameters": [
          {
            "description": "UUID of the cosmetic item to purchase",
            "in": "path",
            "name": "id",
            "required": true,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          }
        ],
        "responses": {
          "201": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "id": {
                      "description": "ID of the user cosmetic record",
                      "format": "uuid",
                      "type": "string"
                    },
                    "acquired_at": {
                      "format": "date-time",
                      "type": "string"
                    }
                  },
                  "required": [
                    "id",
                    "acquired_at"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Purchase successful"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          },
          "402": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Insufficient points"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Item not found"
          },
          "409": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Item already owned"
          },
          "410": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Item no longer available"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Purchase a cosmetic item",
        "tags": [
          "Social"
        ]
      }
    },
    "/api/social/cosmetics/inventory": {
      "get": {
        "description": "Returns all cosmetic items owned by the authenticated user, including item details.",
        "operationId": "getInventory",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "items": {
                      "items": {
                        "$ref": "#/components/schemas/UserCosmetic"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "items"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "User's cosmetic inventory"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized â€” missing or invalid JWT"
          }
        },
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "summary": "Get the current user's cosmetic inventory",
        "tags": [
          "Social"
        ]
      }
    },
    "/api/v1/ads/campaigns": {
      "get": {
        "tags": [
          "ads-marketplace"
        ],
        "summary": "List ad campaigns",
        "description": "Retrieves a paginated list of the operator's campaigns.",
        "operationId": "listAdCampaigns",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "paused",
                "draft",
                "completed"
              ]
            }
          },
          {
            "name": "surface_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "banner",
                "video",
                "interstitial",
                "native",
                "rewarded"
              ]
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Paginated list of campaigns"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      },
      "post": {
        "tags": [
          "ads-marketplace"
        ],
        "summary": "Create a campaign",
        "description": "Creates a new ad campaign owned by the calling app.",
        "operationId": "createAdCampaign",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "surface_type",
                  "budget",
                  "payout_rate"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "surface_type": {
                    "type": "string",
                    "enum": [
                      "banner",
                      "video",
                      "interstitial",
                      "native",
                      "rewarded"
                    ]
                  },
                  "budget": {
                    "type": "integer"
                  },
                  "payout_rate": {
                    "type": "integer"
                  },
                  "bitcoin_tier": {
                    "type": "boolean"
                  },
                  "targeting_metadata": {
                    "type": "object"
                  },
                  "starts_at": {
                    "type": "string",
                    "format": "date-time",
                    "nullable": true
                  },
                  "ends_at": {
                    "type": "string",
                    "format": "date-time",
                    "nullable": true
                  },
                  "segment_ids": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Campaign created"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "description": "Validation failed"
          }
        }
      }
    },
    "/api/v1/ads/campaigns/{id}": {
      "put": {
        "tags": [
          "ads-marketplace"
        ],
        "summary": "Update a campaign",
        "operationId": "updateAdCampaign",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "surface_type": {
                    "type": "string"
                  },
                  "payout_rate": {
                    "type": "integer"
                  },
                  "targeting_metadata": {
                    "type": "object"
                  },
                  "bitcoin_tier": {
                    "type": "boolean"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campaign updated"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "description": "Validation failed"
          }
        }
      },
      "delete": {
        "tags": [
          "ads-marketplace"
        ],
        "summary": "Delete a campaign",
        "description": "Deletes a campaign. Only allowed if the campaign has no spend activity.",
        "operationId": "deleteAdCampaign",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Deleted successfully"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "422": {
            "description": "Delete not allowed"
          }
        }
      }
    },
    "/api/v1/ads/campaigns/{id}/pause": {
      "post": {
        "tags": [
          "ads-marketplace"
        ],
        "summary": "Pause a campaign",
        "operationId": "pauseAdCampaign",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Campaign paused"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "description": "Campaign is not active"
          }
        }
      }
    },
    "/api/v1/ads/campaigns/{id}/resume": {
      "post": {
        "tags": [
          "ads-marketplace"
        ],
        "summary": "Resume a campaign",
        "operationId": "resumeAdCampaign",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Campaign resumed"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "description": "Campaign is not paused"
          }
        }
      }
    },
    "/api/v1/ads/segments": {
      "get": {
        "tags": [
          "ads-marketplace"
        ],
        "summary": "List audience segments",
        "description": "Returns all available audience segments for campaign targeting.",
        "operationId": "listAudienceSegments",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Segment list"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/v1/ads/campaigns/{id}/targeting": {
      "get": {
        "tags": [
          "ads-marketplace"
        ],
        "summary": "Get campaign targeting",
        "operationId": "getAdCampaignTargeting",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Targeting config"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      },
      "post": {
        "tags": [
          "ads-marketplace"
        ],
        "summary": "Set campaign targeting",
        "operationId": "setAdCampaignTargeting",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "segment_ids": {
                    "type": "array",
                    "items": {
                      "type": "string",
                      "format": "uuid"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Targeting updated"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "description": "Targeting update failed"
          }
        }
      }
    },
    "/api/v1/ads/analytics/overview": {
      "get": {
        "tags": [
          "ads-marketplace"
        ],
        "summary": "Analytics overview",
        "description": "Aggregate analytics dashboard for the operator's app.",
        "operationId": "getAdAnalyticsOverview",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Overview dashboard"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/v1/ads/analytics/campaign/{id}": {
      "get": {
        "tags": [
          "ads-marketplace"
        ],
        "summary": "Campaign analytics",
        "description": "Performance stats for a specific campaign.",
        "operationId": "getAdCampaignAnalytics",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Campaign stats"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          }
        }
      }
    },
    "/api/v1/ads/analytics/placement/{id}": {
      "get": {
        "tags": [
          "ads-marketplace"
        ],
        "summary": "Placement analytics",
        "operationId": "getAdPlacementAnalytics",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          },
          {
            "name": "from",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            }
          },
          {
            "name": "to",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "format": "date"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Placement stats"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/v1/ads/pricing/rates": {
      "get": {
        "tags": [
          "ads-marketplace"
        ],
        "summary": "List pricing rates",
        "operationId": "listAdPricingRates",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Rate list"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/v1/ads/pricing/rates/{placement_id}": {
      "get": {
        "tags": [
          "ads-marketplace"
        ],
        "summary": "Get rate for surface type",
        "operationId": "getAdPricingRate",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "placement_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Rate detail"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/v1/ads/pricing/bulk-quote": {
      "post": {
        "tags": [
          "ads-marketplace"
        ],
        "summary": "Get bulk pricing quote",
        "operationId": "getAdBulkQuote",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "items"
                ],
                "properties": {
                  "items": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "required": [
                        "surface_type",
                        "quantity"
                      ],
                      "properties": {
                        "surface_type": {
                          "type": "string",
                          "enum": [
                            "banner",
                            "video",
                            "interstitial",
                            "native",
                            "rewarded"
                          ]
                        },
                        "quantity": {
                          "type": "integer",
                          "minimum": 1
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Pricing quote"
          },
          "400": {
            "description": "No items provided"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/api/v1/ads/purchases/bulk": {
      "post": {
        "tags": [
          "ads-marketplace"
        ],
        "summary": "Execute bulk purchase",
        "description": "Atomically debits the operator's app_account and credits the campaign budget.",
        "operationId": "executeAdBulkPurchase",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "items",
                  "campaign_id"
                ],
                "properties": {
                  "items": {
                    "type": "array",
                    "items": {
                      "type": "object"
                    }
                  },
                  "campaign_id": {
                    "type": "string",
                    "format": "uuid"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Purchase settled"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "402": {
            "description": "Insufficient balance"
          },
          "422": {
            "description": "Invalid items or missing app account"
          },
          "500": {
            "description": "Settlement failed"
          }
        }
      }
    },
    "/api/external/campaigns": {
      "get": {
        "tags": [
          "external-campaigns"
        ],
        "summary": "List operator campaigns",
        "description": "Returns paginated campaigns owned by the authenticated operator. Requires campaign:read scope.",
        "operationId": "listExternalCampaigns",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "status",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "active",
                "paused",
                "draft",
                "completed",
                "cancelled"
              ]
            }
          },
          {
            "name": "surface_type",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "name": "page",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 1
            }
          },
          {
            "name": "page_size",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "default": 20
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Campaign list"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          }
        }
      },
      "post": {
        "tags": [
          "external-campaigns"
        ],
        "summary": "Create an operator campaign",
        "description": "Creates a new campaign funded from the operator's app account. A 10% platform rake is applied. Requires campaign:write scope.",
        "operationId": "createExternalCampaign",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": [
                  "name",
                  "surface_type",
                  "budget",
                  "payout_rate"
                ],
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "surface_type": {
                    "type": "string",
                    "enum": [
                      "banner",
                      "video",
                      "interstitial",
                      "native",
                      "rewarded"
                    ]
                  },
                  "budget": {
                    "type": "integer",
                    "description": "Gross budget in Buddo points. 10% rake deducted."
                  },
                  "payout_rate": {
                    "type": "integer"
                  },
                  "bitcoin_tier": {
                    "type": "boolean"
                  },
                  "targeting_metadata": {
                    "type": "object",
                    "nullable": true
                  },
                  "starts_at": {
                    "type": "string",
                    "format": "date-time",
                    "nullable": true
                  },
                  "ends_at": {
                    "type": "string",
                    "format": "date-time",
                    "nullable": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Campaign created"
          },
          "400": {
            "description": "Missing required field"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "422": {
            "description": "Business logic error"
          }
        }
      }
    },
    "/api/external/campaigns/{id}": {
      "get": {
        "tags": [
          "external-campaigns"
        ],
        "summary": "Get a campaign",
        "description": "Returns a single campaign owned by the operator. Requires campaign:read scope.",
        "operationId": "getExternalCampaign",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Campaign"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Campaign not found"
          }
        }
      },
      "put": {
        "tags": [
          "external-campaigns"
        ],
        "summary": "Update a campaign",
        "description": "Updates mutable fields. Requires campaign:write scope.",
        "operationId": "updateExternalCampaign",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "properties": {
                  "name": {
                    "type": "string"
                  },
                  "surface_type": {
                    "type": "string"
                  },
                  "payout_rate": {
                    "type": "integer"
                  },
                  "targeting_metadata": {
                    "type": "object",
                    "nullable": true
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Campaign updated"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Campaign not found"
          },
          "422": {
            "description": "Validation failed"
          }
        }
      },
      "delete": {
        "tags": [
          "external-campaigns"
        ],
        "summary": "Cancel a campaign",
        "description": "Cancels the campaign and refunds the remaining net budget. Requires campaign:manage scope.",
        "operationId": "cancelExternalCampaign",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "format": "uuid"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Campaign cancelled with refund"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          },
          "403": {
            "$ref": "#/components/responses/Forbidden"
          },
          "404": {
            "description": "Campaign not found"
          },
          "422": {
            "description": "App account not found"
          }
        }
      }
    },
    "/api/deploy/sandbox-status": {
      "get": {
        "tags": [
          "deploy"
        ],
        "summary": "Check sandbox deployment eligibility",
        "description": "Returns sandbox deployment eligibility and current container usage limits. Requires deploy:manage scope.",
        "operationId": "getDeploySandboxStatus",
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Sandbox status"
          },
          "401": {
            "$ref": "#/components/responses/Unauthorized"
          }
        }
      }
    },
    "/.well-known/openapi.json": {
      "get": {
        "operationId": "getOpenApiSpec",
        "responses": {
          "200": {
            "description": "OpenAPI 3.1 spec"
          }
        },
        "summary": "This OpenAPI specification document",
        "tags": [
          "Discovery"
        ]
      }
    },
    "/llms.txt": {
      "get": {
        "operationId": "getLlmsTxt",
        "responses": {
          "200": {
            "description": "Plain text description for LLM agents"
          }
        },
        "summary": "LLM agent discovery file - describes the API for AI agents",
        "tags": [
          "Discovery"
        ]
      }
    },
    "/api/auth/self-verify-email": {
      "post": {
        "description": "Verifies the email of the authenticated user without requiring an OTP code. Used for operator onboarding flows where email trust is established via OAuth. Requires an OAuth access token with the profile:read scope.",
        "operationId": "selfVerifyEmail",
        "responses": {
          "200": {
            "description": "Email verified"
          },
          "401": {
            "description": "Unauthorized"
          }
        },
        "security": [
          {
            "oauth2": [
              "profile:read"
            ]
          }
        ],
        "summary": "Self-verify email for authenticated user (no OTP required)",
        "tags": [
          "Auth"
        ]
      }
    },
    "/api/external/ads/serve/v2": {
      "get": {
        "description": "Selects and returns the best matching campaign placement for the viewer context. Auto-records one impression on the placement on each call (no separate event call needed for impressions on the placement path). Falls back to legacy surface_type campaign selection if no placement matches.",
        "operationId": "serveAdV2",
        "parameters": [
          {
            "description": "Required when surface_id is not provided",
            "in": "query",
            "name": "surface_type",
            "required": false,
            "schema": {
              "enum": [
                "banner",
                "video",
                "interstitial",
                "native",
                "rewarded"
              ],
              "type": "string"
            }
          },
          {
            "description": "Placement UUID for targeted serving. Operator must own at least one campaign placement on this surface.",
            "in": "query",
            "name": "surface_id",
            "required": false,
            "schema": {
              "format": "uuid",
              "type": "string"
            }
          },
          {
            "description": "Game type context for targeting",
            "in": "query",
            "name": "game_type",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Play tier context for targeting",
            "in": "query",
            "name": "play_tier",
            "required": false,
            "schema": {
              "type": "string"
            }
          },
          {
            "description": "Geography context for targeting",
            "in": "query",
            "name": "geo",
            "required": false,
            "schema": {
              "type": "string"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Campaign"
                }
              }
            },
            "description": "Campaign or placement served (impression auto-recorded)"
          },
          "400": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorWithMessage"
                }
              }
            },
            "description": "Bad request - surface_id or surface_type required"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorWithMessage"
                }
              }
            },
            "description": "surface_not_owned - operator does not own campaign placements on this surface"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ErrorWithMessage"
                }
              }
            },
            "description": "No campaign available for context"
          }
        },
        "security": [
          {
            "oauth2": [
              "profile:read"
            ]
          }
        ],
        "summary": "Serve an ad with placement-aware targeting (v2)",
        "tags": [
          "Ads"
        ]
      }
    },
    "/api/operator/billing/history": {
      "get": {
        "operationId": "getBillingHistory",
        "parameters": [
          {
            "description": "Page number (1-indexed)",
            "in": "query",
            "name": "page",
            "required": false,
            "schema": {
              "default": 1,
              "minimum": 1,
              "type": "integer"
            }
          },
          {
            "description": "Number of transactions per page (max 100)",
            "in": "query",
            "name": "page_size",
            "required": false,
            "schema": {
              "default": 20,
              "maximum": 100,
              "minimum": 1,
              "type": "integer"
            }
          }
        ],
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "properties": {
                    "page": {
                      "type": "integer"
                    },
                    "page_size": {
                      "type": "integer"
                    },
                    "total": {
                      "type": "integer"
                    },
                    "transactions": {
                      "items": {
                        "properties": {
                          "amount": {
                            "type": "integer"
                          },
                          "description": {
                            "type": [
                              "string",
                              "null"
                            ]
                          },
                          "id": {
                            "format": "uuid",
                            "type": "string"
                          },
                          "inserted_at": {
                            "format": "date-time",
                            "type": "string"
                          },
                          "transaction_type": {
                            "type": "string"
                          }
                        },
                        "required": [
                          "id",
                          "amount",
                          "transaction_type",
                          "inserted_at"
                        ],
                        "type": "object"
                      },
                      "type": "array"
                    }
                  },
                  "required": [
                    "transactions",
                    "total",
                    "page",
                    "page_size"
                  ],
                  "type": "object"
                }
              }
            },
            "description": "Paginated billing history"
          },
          "401": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Unauthorized"
          },
          "403": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "Forbidden - token does not belong to the app owner"
          },
          "404": {
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            },
            "description": "App or app account not found"
          }
        },
        "security": [
          {
            "oauth2": [
              "app:balance:read"
            ]
          }
        ],
        "summary": "Get paginated billing history for the operator app account",
        "tags": [
          "Operator"
        ]
      }
    },
    "/.well-known/oauth-protected-resource": {
      "get": {
        "description": "RFC 9728 OAuth Protected Resource Metadata. Returns the list of supported scopes, capability descriptions, authorization server, and token endpoint. No authentication required.",
        "operationId": "getOAuthProtectedResourceMetadata",
        "responses": {
          "200": {
            "content": {
              "application/json": {
                "schema": {
                  "description": "RFC 9728 OAuth 2.0 Protected Resource Metadata. Returns server capabilities, supported scopes, and endpoint discovery information.",
                  "properties": {
                    "resource": {
                      "type": "string",
                      "description": "The resource server identifier URI"
                    },
                    "authorization_endpoint": {
                      "type": "string"
                    },
                    "authorization_servers": {
                      "items": {
                        "type": "string"
                      },
                      "type": "array"
                    },
                    "bearer_methods_supported": {
                      "items": {
                        "type": "string"
                      },
                      "type": "array"
                    },
                    "capabilities": {
                      "items": {
                        "properties": {
                          "description": {
                            "type": "string"
                          },
                          "method": {
                            "type": "string"
                          },
                          "path": {
                            "type": "string"
                          },
                          "rate_limit": {
                            "type": "string"
                          },
                          "scope": {
                            "type": "string"
                          }
                        },
                        "type": "object"
                      },
                      "type": "array"
                    },
                    "scope_descriptions": {
                      "additionalProperties": {
                        "type": "string"
                      },
                      "type": "object"
                    },
                    "scopes_supported": {
                      "items": {
                        "type": "string"
                      },
                      "type": "array"
                    },
                    "token_endpoint": {
                      "type": "string"
                    }
                  },
                  "type": "object"
                }
              }
            },
            "description": "OAuth Protected Resource Metadata"
          }
        },
        "summary": "OAuth 2.0 Protected Resource discovery (RFC 9728)",
        "tags": [
          "Discovery"
        ]
      }
    }
  },
  "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"
  }
}