Skip to content

Reference

Xbox Live Client

Basic factory that stores :class:XboxLiveLanguage, User authorization data and available Providers

pythonxbox.api.client.log = logging.getLogger('xbox.api') module-attribute

pythonxbox.api.client.Session(auth_mgr)

Source code in src/pythonxbox/api/client.py
def __init__(self, auth_mgr: AuthenticationManager) -> None:
    self._auth_mgr = auth_mgr
    self._cv = CorrelationVector()

request(method, url, include_auth=True, include_cv=True, **kwargs) async

Proxy Request and add Auth/CV headers.

Source code in src/pythonxbox/api/client.py
async def request(
    self,
    method: str,
    url: str,
    include_auth: bool = True,
    include_cv: bool = True,
    **kwargs: Any,
) -> Response:
    """Proxy Request and add Auth/CV headers."""
    headers = kwargs.pop("headers", {})
    params = kwargs.pop("params", None)
    data = kwargs.pop("data", None)

    # Extra, user supplied values
    extra_headers = kwargs.pop("extra_headers", None)
    extra_params = kwargs.pop("extra_params", None)
    extra_data = kwargs.pop("extra_data", None)

    # Rate limit object
    rate_limits: RateLimit = kwargs.pop("rate_limits", None)

    if include_auth:
        # Ensure tokens valid
        await self._auth_mgr.refresh_tokens()
        # Set auth header
        headers["Authorization"] = (
            self._auth_mgr.xsts_token.authorization_header_value
        )

    if include_cv:
        headers["MS-CV"] = self._cv.increment()

    # Extend with optionally supplied values
    if extra_headers:
        headers.update(extra_headers)
    if extra_params:
        # query parameters
        params = params or {}
        params.update(extra_params)
    if extra_data:
        # form encoded post data
        data = data or {}
        data.update(extra_data)

    if rate_limits and rate_limits.is_exceeded():
        # Check if rate limits have been exceeded for this endpoint
        raise RateLimitExceededException("Rate limit exceeded", rate_limits)

    response = await self._auth_mgr.session.request(
        method, url, **kwargs, headers=headers, params=params, data=data
    )

    if rate_limits:
        rate_limits.increment()

    return response

get(url, **kwargs) async

Source code in src/pythonxbox/api/client.py
async def get(self, url: str, **kwargs: Any) -> Response:
    return await self.request("GET", url, **kwargs)

options(url, **kwargs) async

Source code in src/pythonxbox/api/client.py
async def options(self, url: str, **kwargs: Any) -> Response:
    return await self.request("OPTIONS", url, **kwargs)

head(url, **kwargs) async

Source code in src/pythonxbox/api/client.py
async def head(self, url: str, **kwargs: Any) -> Response:
    return await self.request("HEAD", url, **kwargs)

post(url, **kwargs) async

Source code in src/pythonxbox/api/client.py
async def post(self, url: str, **kwargs: Any) -> Response:
    return await self.request("POST", url, **kwargs)

put(url, **kwargs) async

Source code in src/pythonxbox/api/client.py
async def put(self, url: str, **kwargs: Any) -> Response:
    return await self.request("PUT", url, **kwargs)

patch(url, **kwargs) async

Source code in src/pythonxbox/api/client.py
async def patch(self, url: str, **kwargs: Any) -> Response:
    return await self.request("PATCH", url, **kwargs)

delete(url, **kwargs) async

Source code in src/pythonxbox/api/client.py
async def delete(self, url: str, **kwargs: Any) -> Response:
    return await self.request("DELETE", url, **kwargs)

pythonxbox.api.client.XboxLiveClient(auth_mgr, language=DefaultXboxLiveLanguages.United_States)

Source code in src/pythonxbox/api/client.py
def __init__(
    self,
    auth_mgr: AuthenticationManager,
    language: XboxLiveLanguage = DefaultXboxLiveLanguages.United_States,
) -> None:
    self._auth_mgr = auth_mgr
    self.session = Session(auth_mgr)
    self._language = language

    self.cqs = CQSProvider(self)
    self.lists = ListsProvider(self)
    self.profile = ProfileProvider(self)
    self.achievements = AchievementsProvider(self)
    self.usersearch = UserSearchProvider(self)
    self.gameclips = GameclipProvider(self)
    self.people = PeopleProvider(self)
    self.presence = PresenceProvider(self)
    self.mediahub = MediahubProvider(self)
    self.message = MessageProvider(self)
    self.userstats = UserStatsProvider(self)
    self.screenshots = ScreenshotsProvider(self)
    self.titlehub = TitlehubProvider(self)
    self.account = AccountProvider(self)
    self.catalog = CatalogProvider(self)
    self.smartglass = SmartglassProvider(self)

session = Session(auth_mgr) instance-attribute

cqs = CQSProvider(self) instance-attribute

lists = ListsProvider(self) instance-attribute

profile = ProfileProvider(self) instance-attribute

achievements = AchievementsProvider(self) instance-attribute

usersearch = UserSearchProvider(self) instance-attribute

gameclips = GameclipProvider(self) instance-attribute

people = PeopleProvider(self) instance-attribute

presence = PresenceProvider(self) instance-attribute

mediahub = MediahubProvider(self) instance-attribute

message = MessageProvider(self) instance-attribute

userstats = UserStatsProvider(self) instance-attribute

screenshots = ScreenshotsProvider(self) instance-attribute

titlehub = TitlehubProvider(self) instance-attribute

account = AccountProvider(self) instance-attribute

catalog = CatalogProvider(self) instance-attribute

smartglass = SmartglassProvider(self) instance-attribute

xuid property

Gets the Xbox User ID

Returns: Xbox user Id

language property

Gets the active Xbox Live Language

Returns: Active Xbox Live language

Language definitions

pythonxbox.api.language.XboxLiveLanguage(name, short_id, identifier, locale)

Initialize a new instance of :class:XboxLiveLanguage

Parameters:

Name Type Description Default
name str

Full name describing the language / country

required
short_id str

Short Id (e.g. "AT" for Austria)

required
identifier str

Identifier (e.g. "de_AT" for Austria)

required
locale str

Locale (e.g. "de-AT" for Austria)

required
Source code in src/pythonxbox/api/language.py
def __init__(
    self,
    name: str,
    short_id: str,
    identifier: str,
    locale: str,
) -> None:
    """
    Initialize a new instance of :class:`XboxLiveLanguage`

    Args:
        name (str): Full name describing the language / country
        short_id (str): Short Id (e.g. "AT" for Austria)
        identifier (str): Identifier (e.g. "de_AT" for Austria)
        locale (str): Locale (e.g. "de-AT" for Austria)
    """
    self.name = name
    self.short_id = short_id
    self.identifier = identifier
    self.locale = locale

name = name instance-attribute

short_id = short_id instance-attribute

identifier = identifier instance-attribute

locale = locale instance-attribute

pythonxbox.api.language.DefaultXboxLiveLanguages

Collection of locales compatible with XBL

Argentina = XboxLiveLanguage('Argentina', 'AR', 'es_AR', 'es-AR') class-attribute instance-attribute

Australia = XboxLiveLanguage('Australia', 'AU', 'en_AU', 'en-AU') class-attribute instance-attribute

Austria = XboxLiveLanguage('Austria', 'AT', 'de_AT', 'de-AT') class-attribute instance-attribute

Belgium = XboxLiveLanguage('Belgium', 'BE', 'fr_BE', 'fr-BE') class-attribute instance-attribute

Belgium_NL = XboxLiveLanguage('Belgium (NL)', 'NL', 'nl_BE', 'nl-BE') class-attribute instance-attribute

Brazil = XboxLiveLanguage('Brazil', 'BR', 'pt_BR', 'pt-BR') class-attribute instance-attribute

Canada = XboxLiveLanguage('Canada', 'CA', 'en_CA', 'en-CA') class-attribute instance-attribute

Canada_FR = XboxLiveLanguage('Canada (FR)', 'CA', 'fr_CA', 'fr-CA') class-attribute instance-attribute

Czech_Republic = XboxLiveLanguage('Czech Republic', 'CZ', 'en_CZ', 'en-CZ') class-attribute instance-attribute

Denmark = XboxLiveLanguage('Denmark', 'DK', 'da_DK', 'da-DK') class-attribute instance-attribute

Finland = XboxLiveLanguage('Finland', 'FI', 'fi_FI', 'fi-FI') class-attribute instance-attribute

France = XboxLiveLanguage('France', 'FR', 'fr_FR', 'fr-FR') class-attribute instance-attribute

Germany = XboxLiveLanguage('Germany', 'DE', 'de_DE', 'de-DE') class-attribute instance-attribute

Greece = XboxLiveLanguage('Greece', 'GR', 'en_GR', 'en-GR') class-attribute instance-attribute

Hong_Kong = XboxLiveLanguage('Hong Kong', 'HK', 'en_HK', 'en-HK') class-attribute instance-attribute

Hungary = XboxLiveLanguage('Hungary', 'HU', 'en_HU', 'en-HU') class-attribute instance-attribute

India = XboxLiveLanguage('India', 'IN', 'en_IN', 'en-IN') class-attribute instance-attribute

Great_Britain = XboxLiveLanguage('Great Britain', 'GB', 'en_GB', 'en-GB') class-attribute instance-attribute

Israel = XboxLiveLanguage('Israel', 'IL', 'en_IL', 'en-IL') class-attribute instance-attribute

Italy = XboxLiveLanguage('Italy', 'IT', 'it_IT', 'it-IT') class-attribute instance-attribute

Japan = XboxLiveLanguage('Japan', 'JP', 'ja_JP', 'ja-JP') class-attribute instance-attribute

Mexico = XboxLiveLanguage('Mexico', 'MX', 'es_MX', 'es-MX') class-attribute instance-attribute

Chile = XboxLiveLanguage('Chile', 'CL', 'es_CL', 'es-CL') class-attribute instance-attribute

Colombia = XboxLiveLanguage('Colombia', 'CO', 'es_CO', 'es-CO') class-attribute instance-attribute

Netherlands = XboxLiveLanguage('Netherlands', 'NL', 'nl_NL', 'nl-NL') class-attribute instance-attribute

New_Zealand = XboxLiveLanguage('New Zealand', 'NZ', 'en_NZ', 'en-NZ') class-attribute instance-attribute

Norway = XboxLiveLanguage('Norway', 'NO', 'nb_NO', 'nb-NO') class-attribute instance-attribute

Poland = XboxLiveLanguage('Poland', 'PL', 'pl_PL', 'pl-PL') class-attribute instance-attribute

Portugal = XboxLiveLanguage('Portugal', 'PT', 'pt_PT', 'pt-PT') class-attribute instance-attribute

Russia = XboxLiveLanguage('Russia', 'RU', 'ru_RU', 'ru-RU') class-attribute instance-attribute

Saudi_Arabia = XboxLiveLanguage('Saudi Arabia', 'SA', 'en_SA', 'en-SA') class-attribute instance-attribute

Singapore = XboxLiveLanguage('Singapore', 'SG', 'en_SG', 'en-SG') class-attribute instance-attribute

Slovakia = XboxLiveLanguage('Slovakia', 'SK', 'en_SK', 'en-SK') class-attribute instance-attribute

South_Africa = XboxLiveLanguage('South Afrida', 'ZA', 'en_ZA', 'en-ZA') class-attribute instance-attribute

Korea = XboxLiveLanguage('Korea', 'KR', 'ko_KR', 'ko-KR') class-attribute instance-attribute

Spain = XboxLiveLanguage('Spain', 'ES', 'es_ES', 'es-ES') class-attribute instance-attribute

Switzerland = XboxLiveLanguage('Switzerland', 'CH', 'de_CH', 'de-CH') class-attribute instance-attribute

Switzerland_FR = XboxLiveLanguage('Switzerland (FR)', 'CH', 'fr_CH', 'fr-CH') class-attribute instance-attribute

United_Arab_Emirates = XboxLiveLanguage('United Arab Emirates', 'AE', 'en_AE', 'en-AE') class-attribute instance-attribute

United_States = XboxLiveLanguage('United States', 'US', 'en_US', 'en-US') class-attribute instance-attribute

Ireland = XboxLiveLanguage('Ireland', 'IE', 'en_IE', 'en-IE') class-attribute instance-attribute

pythonxbox.api.provider.account.AccountProvider(client)

Bases: BaseProvider

Source code in src/pythonxbox/api/provider/baseprovider.py
def __init__(self, client: "XboxLiveClient") -> None:
    """
    Initialize an the BaseProvider

    Args:
        client (:class:`XboxLiveClient`): Instance of XboxLiveClient
    """
    self.client = client

BASE_URL_USER_MGT = 'https://user.mgt.xboxlive.com' class-attribute instance-attribute

BASE_URL_ACCOUNT = 'https://accounts.xboxlive.com' class-attribute instance-attribute

HEADERS_USER_MGT = {'x-xbl-contract-version': '1'} class-attribute instance-attribute

HEADERS_ACCOUNT = {'x-xbl-contract-version': '2'} class-attribute instance-attribute

claim_gamertag(xuid, gamertag, **kwargs) async

Claim gamertag

XLE error codes

400 - Bad API request 401 - Unauthorized 409 - Gamertag unavailable 429 - Too many requests 200 - Gamertag available

Parameters:

Name Type Description Default
xuid int

Your xuid as integer

required
gamertag str

Desired gamertag

required

Returns: ClaimGamertagResult

Source code in src/pythonxbox/api/provider/account/__init__.py
async def claim_gamertag(
    self, xuid: str, gamertag: str, **kwargs
) -> ClaimGamertagResult:
    """
    Claim gamertag

    XLE error codes:
        400 - Bad API request
        401 - Unauthorized
        409 - Gamertag unavailable
        429 - Too many requests
        200 - Gamertag available

    Args:
        xuid (int): Your xuid as integer
        gamertag (str): Desired gamertag

    Returns: ClaimGamertagResult
    """
    url = self.BASE_URL_USER_MGT + "/gamertags/reserve"
    post_data = {"Gamertag": gamertag, "ReservationId": str(xuid)}
    resp = await self.client.session.post(
        url, json=post_data, headers=self.HEADERS_USER_MGT, **kwargs
    )
    try:
        return ClaimGamertagResult(resp.status_code)
    except ValueError:
        resp.raise_for_status()

change_gamertag(xuid, gamertag, preview=False, **kwargs) async

Change your gamertag.

XLE error codes

200 - success 1020 - No free gamertag changes available

Parameters:

Name Type Description Default
xuid int

Your Xuid as integer

required
gamertag str

Desired gamertag name

required
preview bool

Preview the change

False

Returns: ChangeGamertagResult

Source code in src/pythonxbox/api/provider/account/__init__.py
async def change_gamertag(
    self, xuid: str, gamertag: str, preview: bool = False, **kwargs
) -> ChangeGamertagResult:
    """
    Change your gamertag.

    XLE error codes:
        200 - success
        1020 - No free gamertag changes available

    Args:
        xuid (int): Your Xuid as integer
        gamertag (str): Desired gamertag name
        preview (bool): Preview the change

    Returns: ChangeGamertagResult
    """
    url = self.BASE_URL_ACCOUNT + "/users/current/profile/gamertag"
    post_data = {
        "gamertag": gamertag,
        "preview": preview,
        "reservationId": int(xuid),
    }
    resp = await self.client.session.post(
        url, json=post_data, headers=self.HEADERS_ACCOUNT, **kwargs
    )
    try:
        return ChangeGamertagResult(resp.status_code)
    except ValueError:
        resp.raise_for_status()

pythonxbox.api.provider.account.models.ClaimGamertagResult

Bases: Enum

NotAvailable = 409 class-attribute instance-attribute

Available = 200 class-attribute instance-attribute

pythonxbox.api.provider.account.models.ChangeGamertagResult

Bases: Enum

ChangeSuccessful = 200 class-attribute instance-attribute

NoFreeChangesAvailable = 1020 class-attribute instance-attribute

CQS

Used for download stump (TV Streaming) data (RemoteTVInput ServiceChannel on Smartglass)

pythonxbox.api.provider.cqs.CQSProvider(client)

Bases: BaseProvider

Source code in src/pythonxbox/api/provider/baseprovider.py
def __init__(self, client: "XboxLiveClient") -> None:
    """
    Initialize an the BaseProvider

    Args:
        client (:class:`XboxLiveClient`): Instance of XboxLiveClient
    """
    self.client = client

CQS_URL = 'https://cqs.xboxlive.com' class-attribute instance-attribute

HEADERS_CQS = {'Cache-Control': 'no-cache', 'Accept': 'application/json', 'Pragma': 'no-cache', 'x-xbl-client-type': 'Companion', 'x-xbl-client-version': '2.0', 'x-xbl-contract-version': '1.b', 'x-xbl-device-type': 'WindowsPhone', 'x-xbl-isautomated-client': 'true'} class-attribute instance-attribute

get_channel_list(locale_info, headend_id, **kwargs) async

Get stump channel list

Parameters:

Name Type Description Default
locale_info str

Locale string (format: "en-US")

required
headend_id str

Headend id

required

Returns:

Type Description
CqsChannelListResponse

class:CqsChannelListResponse: Channel List Response

Source code in src/pythonxbox/api/provider/cqs/__init__.py
async def get_channel_list(
    self, locale_info: str, headend_id: str, **kwargs
) -> CqsChannelListResponse:
    """
    Get stump channel list

    Args:
        locale_info: Locale string (format: "en-US")
        headend_id: Headend id

    Returns:
        :class:`CqsChannelListResponse`: Channel List Response
    """
    url = self.CQS_URL + f"/epg/{locale_info}/lineups/{headend_id}/channels"
    params = {"desired": "vesper_mobile_lineup"}
    resp = await self.client.session.get(
        url, params=params, headers=self.HEADERS_CQS, **kwargs
    )
    resp.raise_for_status()
    return CqsChannelListResponse.model_validate_json(resp.text)

get_schedule(locale_info, headend_id, start_date, duration_minutes, channel_skip, channel_count, **kwargs) async

Get stump epg data

Parameters:

Name Type Description Default
locale_info str

Locale string (format: "en-US")

required
headend_id str

Headend id

required
start_date str

Start date (format: 2016-07-11T21:50:00.000Z)

required
duration_minutes int

Schedule duration to download

required
channel_skip int

Count of channels to skip

required
channel_count int

Count of channels to get data for

required

Returns:

Type Description
CqsScheduleResponse

class:CqsScheduleResponse: Schedule Response

Source code in src/pythonxbox/api/provider/cqs/__init__.py
async def get_schedule(  # noqa: PLR0913
    self,
    locale_info: str,
    headend_id: str,
    start_date: str,
    duration_minutes: int,
    channel_skip: int,
    channel_count: int,
    **kwargs,
) -> CqsScheduleResponse:
    """
    Get stump epg data

    Args:
        locale_info: Locale string (format: "en-US")
        headend_id: Headend id
        start_date: Start date (format: 2016-07-11T21:50:00.000Z)
        duration_minutes: Schedule duration to download
        channel_skip: Count of channels to skip
        channel_count: Count of channels to get data for

    Returns:
        :class:`CqsScheduleResponse`: Schedule Response
    """
    url = self.CQS_URL + f"/epg/{locale_info}/lineups/{headend_id}/programs"
    params = {
        "startDate": start_date,
        "durationMinutes": duration_minutes,
        "channelSkip": channel_skip,
        "channelCount": channel_count,
        "desired": "vesper_mobile_schedule",
    }
    resp = await self.client.session.get(
        url, params=params, headers=self.HEADERS_CQS, **kwargs
    )
    resp.raise_for_status()
    return CqsScheduleResponse.model_validate_json(resp.text)

pythonxbox.api.provider.cqs.models.Image

Bases: PascalCaseModel

purpose instance-attribute

resize_uri instance-attribute

fore_color instance-attribute

pythonxbox.api.provider.cqs.models.ListChannel

Bases: PascalCaseModel

id instance-attribute

channel_id instance-attribute

call_sign instance-attribute

channel_number instance-attribute

start_date instance-attribute

end_date instance-attribute

images instance-attribute

is_HD = None class-attribute instance-attribute

pythonxbox.api.provider.cqs.models.CqsChannelListResponse

Bases: PascalCaseModel

channels instance-attribute

pythonxbox.api.provider.cqs.models.Genre

Bases: PascalCaseModel

name instance-attribute

pythonxbox.api.provider.cqs.models.ParentSeries

Bases: PascalCaseModel

id instance-attribute

name instance-attribute

pythonxbox.api.provider.cqs.models.Program

Bases: PascalCaseModel

id instance-attribute

media_item_type instance-attribute

start_date instance-attribute

end_date instance-attribute

name instance-attribute

is_repeat instance-attribute

parental_control = None class-attribute instance-attribute

genres instance-attribute

category_id instance-attribute

description = None class-attribute instance-attribute

parent_series = None class-attribute instance-attribute

images = None class-attribute instance-attribute

pythonxbox.api.provider.cqs.models.ScheduleChannel

Bases: PascalCaseModel

id instance-attribute

name instance-attribute

images instance-attribute

programs instance-attribute

pythonxbox.api.provider.cqs.models.CqsScheduleResponse

Bases: PascalCaseModel

channels instance-attribute

Gameclips - Get gameclip info

pythonxbox.api.provider.gameclips.GameclipProvider(client)

Bases: BaseProvider

Source code in src/pythonxbox/api/provider/baseprovider.py
def __init__(self, client: "XboxLiveClient") -> None:
    """
    Initialize an the BaseProvider

    Args:
        client (:class:`XboxLiveClient`): Instance of XboxLiveClient
    """
    self.client = client

GAMECLIPS_METADATA_URL = 'https://gameclipsmetadata.xboxlive.com' class-attribute instance-attribute

HEADERS_GAMECLIPS_METADATA = {'x-xbl-contract-version': '1'} class-attribute instance-attribute

get_recent_community_clips_by_title_id(title_id, **kwargs) async

Get recent community clips by Title Id

Parameters:

Name Type Description Default
title_id str

Title Id to get clips for

required

Returns:

Type Description
GameclipsResponse

class:GameclipsResponse: Game clip Response

Source code in src/pythonxbox/api/provider/gameclips/__init__.py
async def get_recent_community_clips_by_title_id(
    self, title_id: str, **kwargs
) -> GameclipsResponse:
    """
    Get recent community clips by Title Id

    Args:
        title_id: Title Id to get clips for

    Returns:
        :class:`GameclipsResponse`: Game clip Response
    """
    url = self.GAMECLIPS_METADATA_URL + f"/public/titles/{title_id}/clips"
    params = {"qualifier": "created"}
    resp = await self.client.session.get(
        url, params=params, headers=self.HEADERS_GAMECLIPS_METADATA, **kwargs
    )
    resp.raise_for_status()
    return GameclipsResponse.model_validate_json(resp.text)

get_recent_own_clips(title_id=None, skip_items=0, max_items=25, **kwargs) async

Get own recent clips, optionally filter for title Id

Parameters:

Name Type Description Default
title_id str | None

Title ID to filter

None
skip_items int

Item count to skip

0
max_items int

Maximum item count to load

25

Returns:

Type Description
GameclipsResponse

class:GameclipsResponse: Game clip Response

Source code in src/pythonxbox/api/provider/gameclips/__init__.py
async def get_recent_own_clips(
    self,
    title_id: str | None = None,
    skip_items: int = 0,
    max_items: int = 25,
    **kwargs,
) -> GameclipsResponse:
    """
    Get own recent clips, optionally filter for title Id

    Args:
        title_id: Title ID to filter
        skip_items: Item count to skip
        max_items: Maximum item count to load

    Returns:
        :class:`GameclipsResponse`: Game clip Response
    """
    url = self.GAMECLIPS_METADATA_URL + "/users/me"
    if title_id:
        url += f"/titles/{title_id}"
    url += "/clips"

    params = {"skipItems": skip_items, "maxItems": max_items}
    resp = await self.client.session.get(
        url, params=params, headers=self.HEADERS_GAMECLIPS_METADATA, **kwargs
    )
    resp.raise_for_status()
    return GameclipsResponse.model_validate_json(resp.text)

get_recent_clips_by_xuid(xuid, title_id=None, skip_items=0, max_items=25, **kwargs) async

Get clips by XUID, optionally filter for title Id

Parameters:

Name Type Description Default
xuid str

XUID of user to get clips from

required
title_id str | None

Optional title id filter

None
skip_items int

Item count to skip

0
max_items int

Maximum item count to load

25

Returns:

Type Description
GameclipsResponse

class:GameclipsResponse: Game clip Response

Source code in src/pythonxbox/api/provider/gameclips/__init__.py
async def get_recent_clips_by_xuid(
    self,
    xuid: str,
    title_id: str | None = None,
    skip_items: int = 0,
    max_items: int = 25,
    **kwargs,
) -> GameclipsResponse:
    """
    Get clips by XUID, optionally filter for title Id

    Args:
        xuid: XUID of user to get clips from
        title_id: Optional title id filter
        skip_items: Item count to skip
        max_items: Maximum item count to load

    Returns:
        :class:`GameclipsResponse`: Game clip Response
    """
    url = self.GAMECLIPS_METADATA_URL + f"/users/xuid({xuid})"
    if title_id:
        url += f"/titles/{title_id}"
    url += "/clips"

    params = {"skipItems": skip_items, "maxItems": max_items}
    resp = await self.client.session.get(
        url, params=params, headers=self.HEADERS_GAMECLIPS_METADATA, **kwargs
    )
    resp.raise_for_status()
    return GameclipsResponse.model_validate_json(resp.text)

get_saved_community_clips_by_title_id(title_id, **kwargs) async

Get saved community clips by Title Id

Parameters:

Name Type Description Default
title_id str

Title Id to get screenshots for

required

Returns:

Type Description
GameclipsResponse

class:GameclipsResponse: Game clip Response

Source code in src/pythonxbox/api/provider/gameclips/__init__.py
async def get_saved_community_clips_by_title_id(
    self, title_id: str, **kwargs
) -> GameclipsResponse:
    """
    Get saved community clips by Title Id

    Args:
        title_id: Title Id to get screenshots for

    Returns:
        :class:`GameclipsResponse`: Game clip Response
    """
    url = self.GAMECLIPS_METADATA_URL + f"/public/titles/{title_id}/clips/saved"
    params = {"qualifier": "created"}
    resp = await self.client.session.get(
        url, params=params, headers=self.HEADERS_GAMECLIPS_METADATA, **kwargs
    )
    resp.raise_for_status()
    return GameclipsResponse.model_validate_json(resp.text)

get_saved_own_clips(title_id=None, skip_items=0, max_items=25, **kwargs) async

Get own saved clips, optionally filter for title Id an

Parameters:

Name Type Description Default
title_id str | None

Optional Title ID to filter

None
skip_items int

Item count to skip

0
max_items int

Maximum item count to load

25

Returns:

Type Description
GameclipsResponse

class:GameclipsResponse: Game clip Response

Source code in src/pythonxbox/api/provider/gameclips/__init__.py
async def get_saved_own_clips(
    self,
    title_id: str | None = None,
    skip_items: int = 0,
    max_items: int = 25,
    **kwargs,
) -> GameclipsResponse:
    """
    Get own saved clips, optionally filter for title Id an

    Args:
        title_id: Optional Title ID to filter
        skip_items: Item count to skip
        max_items: Maximum item count to load

    Returns:
        :class:`GameclipsResponse`: Game clip Response
    """
    url = self.GAMECLIPS_METADATA_URL + "/users/me"
    if title_id:
        url += f"/titles/{title_id}"
    url += "/clips/saved"

    params = {"skipItems": skip_items, "maxItems": max_items}
    resp = await self.client.session.get(
        url, params=params, headers=self.HEADERS_GAMECLIPS_METADATA, **kwargs
    )
    resp.raise_for_status()
    return GameclipsResponse.model_validate_json(resp.text)

get_saved_clips_by_xuid(xuid, title_id=None, skip_items=0, max_items=25, **kwargs) async

Get saved clips by XUID, optionally filter for title Id

Parameters:

Name Type Description Default
xuid str

XUID of user to get screenshots from

required
title_id str | None

Optional title id filter

None
skip_items int

Item count to skip

0
max_items int

Maximum item count to load

25

Returns:

Type Description
GameclipsResponse

class:GameclipsResponse: Game clip Response

Source code in src/pythonxbox/api/provider/gameclips/__init__.py
async def get_saved_clips_by_xuid(
    self,
    xuid: str,
    title_id: str | None = None,
    skip_items: int = 0,
    max_items: int = 25,
    **kwargs,
) -> GameclipsResponse:
    """
    Get saved clips by XUID, optionally filter for title Id

    Args:
        xuid: XUID of user to get screenshots from
        title_id: Optional title id filter
        skip_items: Item count to skip
        max_items: Maximum item count to load

    Returns:
        :class:`GameclipsResponse`: Game clip Response
    """
    url = self.GAMECLIPS_METADATA_URL + f"/users/xuid({xuid})"
    if title_id:
        url += f"/titles/{title_id}"
    url += "/clips/saved"

    params = {"skipItems": skip_items, "maxItems": max_items}
    resp = await self.client.session.get(
        url, params=params, headers=self.HEADERS_GAMECLIPS_METADATA, **kwargs
    )
    resp.raise_for_status()
    return GameclipsResponse.model_validate_json(resp.text)

pythonxbox.api.provider.gameclips.models.Thumbnail

Bases: CamelCaseModel

uri instance-attribute

file_size instance-attribute

thumbnail_type instance-attribute

pythonxbox.api.provider.gameclips.models.GameClipUri

Bases: CamelCaseModel

uri instance-attribute

file_size instance-attribute

uri_type instance-attribute

expiration instance-attribute

pythonxbox.api.provider.gameclips.models.GameClip

Bases: CamelCaseModel

game_clip_id instance-attribute

state instance-attribute

date_published instance-attribute

date_recorded instance-attribute

last_modified instance-attribute

user_caption instance-attribute

type instance-attribute

duration_in_seconds instance-attribute

scid instance-attribute

title_id instance-attribute

rating instance-attribute

rating_count instance-attribute

views instance-attribute

title_data instance-attribute

system_properties instance-attribute

saved_by_user instance-attribute

achievement_id instance-attribute

greatest_moment_id instance-attribute

thumbnails instance-attribute

game_clip_uris instance-attribute

xuid instance-attribute

clip_name instance-attribute

title_name instance-attribute

game_clip_locale instance-attribute

clip_content_attributes instance-attribute

device_type instance-attribute

comment_count instance-attribute

like_count instance-attribute

share_count instance-attribute

partial_views instance-attribute

pythonxbox.api.provider.gameclips.models.PagingInfo

Bases: CamelCaseModel

continuation_token = None class-attribute instance-attribute

pythonxbox.api.provider.gameclips.models.GameclipsResponse

Bases: CamelCaseModel

game_clips instance-attribute

paging_info instance-attribute

EPLists - Mainly used for XBL Pins

pythonxbox.api.provider.lists.ListsProvider(client)

Bases: BaseProvider

Source code in src/pythonxbox/api/provider/baseprovider.py
def __init__(self, client: "XboxLiveClient") -> None:
    """
    Initialize an the BaseProvider

    Args:
        client (:class:`XboxLiveClient`): Instance of XboxLiveClient
    """
    self.client = client

LISTS_URL = 'https://eplists.xboxlive.com' class-attribute instance-attribute

HEADERS_LISTS = {'Content-Type': 'application/json', 'x-xbl-contract-version': '2'} class-attribute instance-attribute

SEPERATOR = '.' class-attribute instance-attribute

remove_items(xuid, post_body, listname='XBLPins', **kwargs) async

Remove items from specific list, defaults to "XBLPins"

Parameters:

Name Type Description Default
xuid str / int

Xbox User Id

required
listname str

Name of list to edit

'XBLPins'

Returns:

Type Description
ListMetadata

class:ListMetadata: List Metadata Response

Source code in src/pythonxbox/api/provider/lists/__init__.py
async def remove_items(
    self, xuid: str, post_body: dict, listname: str = "XBLPins", **kwargs
) -> ListMetadata:
    """
    Remove items from specific list, defaults to "XBLPins"

    Args:
        xuid (str/int): Xbox User Id
        listname (str): Name of list to edit

    Returns:
        :class:`ListMetadata`: List Metadata Response
    """
    url = self.LISTS_URL + f"/users/xuid({xuid})/lists/PINS/{listname}"
    resp = await self.client.session.delete(
        url, json=post_body, headers=self.HEADERS_LISTS, **kwargs
    )
    resp.raise_for_status()
    return ListMetadata.model_validate_json(resp.text)

get_items(xuid, listname='XBLPins', **kwargs) async

Get items from specific list, defaults to "XBLPins"

Parameters:

Name Type Description Default
xuid str / int

Xbox User Id

required
listname str

Name of list to edit

'XBLPins'

Returns:

Type Description
ListsResponse

class:ListsResponse: List Response

Source code in src/pythonxbox/api/provider/lists/__init__.py
async def get_items(
    self, xuid: str, listname: str = "XBLPins", **kwargs
) -> ListsResponse:
    """
    Get items from specific list, defaults to "XBLPins"

    Args:
        xuid (str/int): Xbox User Id
        listname (str): Name of list to edit

    Returns:
        :class:`ListsResponse`: List Response
    """
    url = self.LISTS_URL + f"/users/xuid({xuid})/lists/PINS/{listname}"
    resp = await self.client.session.get(url, headers=self.HEADERS_LISTS, **kwargs)
    resp.raise_for_status()
    return ListsResponse.model_validate_json(resp.text)

insert_items(xuid, post_body, listname='XBLPins', **kwargs) async

Insert items to specific list, defaults to "XBLPins"

Parameters:

Name Type Description Default
xuid str / int

Xbox User Id

required
listname str

Name of list to edit

'XBLPins'

Returns:

Type Description
ListMetadata

class:ListMetadata: List Metadata Response

Source code in src/pythonxbox/api/provider/lists/__init__.py
async def insert_items(
    self, xuid: str, post_body: dict, listname: str = "XBLPins", **kwargs
) -> ListMetadata:
    """
    Insert items to specific list, defaults to "XBLPins"

    Args:
        xuid (str/int): Xbox User Id
        listname (str): Name of list to edit

    Returns:
        :class:`ListMetadata`: List Metadata Response
    """
    url = self.LISTS_URL + f"/users/xuid({xuid})/lists/PINS/{listname}"
    resp = await self.client.session.post(
        url, json=post_body, headers=self.HEADERS_LISTS, **kwargs
    )
    resp.raise_for_status()
    return ListMetadata.model_validate_json(resp.text)

pythonxbox.api.provider.lists.models.Item

Bases: PascalCaseModel

item_id instance-attribute

content_type instance-attribute

title = None class-attribute instance-attribute

device_type instance-attribute

provider = None class-attribute instance-attribute

provider_id = None class-attribute instance-attribute

pythonxbox.api.provider.lists.models.ListItem

Bases: PascalCaseModel

date_added instance-attribute

date_modified instance-attribute

index instance-attribute

k_value instance-attribute

item instance-attribute

pythonxbox.api.provider.lists.models.ListMetadata

Bases: PascalCaseModel

list_title instance-attribute

list_version instance-attribute

list_count instance-attribute

allow_duplicates instance-attribute

max_list_size instance-attribute

access_setting instance-attribute

pythonxbox.api.provider.lists.models.ListsResponse

Bases: PascalCaseModel

impression_id instance-attribute

list_items instance-attribute

list_metadata instance-attribute

Mediahub - Fetch screenshots and gameclips

pythonxbox.api.provider.mediahub.MediahubProvider(client)

Bases: BaseProvider

Source code in src/pythonxbox/api/provider/baseprovider.py
def __init__(self, client: "XboxLiveClient") -> None:
    """
    Initialize an the BaseProvider

    Args:
        client (:class:`XboxLiveClient`): Instance of XboxLiveClient
    """
    self.client = client

MEDIAHUB_URL = 'https://mediahub.xboxlive.com' class-attribute instance-attribute

HEADERS = {'x-xbl-contract-version': '3'} class-attribute instance-attribute

fetch_own_clips(skip=0, count=500, **kwargs) async

Fetch own clips

Parameters:

Name Type Description Default
skip int

Number of items to skip

0
count int

Max entries to fetch

500

Returns:

Type Description
MediahubGameclips

class:MediahubGameclips: Gameclips

Source code in src/pythonxbox/api/provider/mediahub/__init__.py
async def fetch_own_clips(
    self, skip: int = 0, count: int = 500, **kwargs
) -> MediahubGameclips:
    """
    Fetch own clips

    Args:
        skip: Number of items to skip
        count: Max entries to fetch

    Returns:
        :class:`MediahubGameclips`: Gameclips
    """
    url = f"{self.MEDIAHUB_URL}/gameclips/search"
    post_data = {
        "max": count,
        "query": f"OwnerXuid eq {self.client.xuid}",
        "skip": skip,
    }
    resp = await self.client.session.post(
        url, json=post_data, headers=self.HEADERS, **kwargs
    )
    resp.raise_for_status()
    return MediahubGameclips.model_validate_json(resp.text)

fetch_own_screenshots(skip=0, count=500, **kwargs) async

Fetch own screenshots

Parameters:

Name Type Description Default
skip int

Number of items to skip

0
count int

Max entries to fetch

500

Returns:

Type Description
MediahubScreenshots

class:MediahubScreenshots: Screenshots

Source code in src/pythonxbox/api/provider/mediahub/__init__.py
async def fetch_own_screenshots(
    self, skip: int = 0, count: int = 500, **kwargs
) -> MediahubScreenshots:
    """
    Fetch own screenshots

    Args:
        skip: Number of items to skip
        count: Max entries to fetch

    Returns:
        :class:`MediahubScreenshots`: Screenshots
    """
    url = f"{self.MEDIAHUB_URL}/screenshots/search"
    post_data = {
        "max": count,
        "query": f"OwnerXuid eq {self.client.xuid}",
        "skip": skip,
    }
    resp = await self.client.session.post(
        url, json=post_data, headers=self.HEADERS, **kwargs
    )
    resp.raise_for_status()
    return MediahubScreenshots.model_validate_json(resp.text)

pythonxbox.api.provider.mediahub.models.ContentSegment

Bases: CamelCaseModel

segment_id instance-attribute

creation_type instance-attribute

creator_channel_id = None class-attribute instance-attribute

creator_xuid instance-attribute

record_date instance-attribute

duration_in_seconds instance-attribute

offset instance-attribute

secondary_title_id = None class-attribute instance-attribute

title_id instance-attribute

pythonxbox.api.provider.mediahub.models.ContentLocator

Bases: CamelCaseModel

expiration = None class-attribute instance-attribute

file_size = None class-attribute instance-attribute

locator_type instance-attribute

uri instance-attribute

pythonxbox.api.provider.mediahub.models.GameclipContent

Bases: CamelCaseModel

content_id instance-attribute

content_locators instance-attribute

content_segments instance-attribute

creation_type instance-attribute

duration_in_seconds instance-attribute

local_id instance-attribute

owner_xuid instance-attribute

sandbox_id instance-attribute

shared_to instance-attribute

title_id instance-attribute

title_name instance-attribute

upload_date instance-attribute

upload_language instance-attribute

upload_region instance-attribute

upload_title_id instance-attribute

upload_device_type instance-attribute

comment_count instance-attribute

like_count instance-attribute

share_count instance-attribute

view_count instance-attribute

content_state instance-attribute

enforcement_state instance-attribute

sessions instance-attribute

tournaments instance-attribute

pythonxbox.api.provider.mediahub.models.MediahubGameclips

Bases: CamelCaseModel

values instance-attribute

pythonxbox.api.provider.mediahub.models.ScreenshotContent

Bases: CamelCaseModel

content_id instance-attribute

capture_date instance-attribute

content_locators instance-attribute

local_id instance-attribute

owner_xuid instance-attribute

resolution_height instance-attribute

resolution_width instance-attribute

date_uploaded instance-attribute

sandbox_id instance-attribute

shared_to instance-attribute

title_id instance-attribute

title_name instance-attribute

upload_language instance-attribute

upload_region instance-attribute

upload_title_id instance-attribute

upload_device_type instance-attribute

comment_count instance-attribute

like_count instance-attribute

share_count instance-attribute

view_count instance-attribute

content_state instance-attribute

enforcement_state instance-attribute

sessions instance-attribute

tournaments instance-attribute

pythonxbox.api.provider.mediahub.models.MediahubScreenshots

Bases: CamelCaseModel

values instance-attribute

Message - Read and send messages

TODO: Support group messaging

pythonxbox.api.provider.message.MESSAGE_MAX_LEN = 256 module-attribute

pythonxbox.api.provider.message.MessageProvider(client)

Bases: BaseProvider

Source code in src/pythonxbox/api/provider/baseprovider.py
def __init__(self, client: "XboxLiveClient") -> None:
    """
    Initialize an the BaseProvider

    Args:
        client (:class:`XboxLiveClient`): Instance of XboxLiveClient
    """
    self.client = client

MSG_URL = 'https://xblmessaging.xboxlive.com' class-attribute instance-attribute

HEADERS_MESSAGE = {'x-xbl-contract-version': '1'} class-attribute instance-attribute

HEADERS_HORIZON = {'x-xbl-contract-version': '2'} class-attribute instance-attribute

get_inbox(max_items=100, **kwargs) async

Get messages

Returns:

Type Description
InboxResponse

class:InboxResponse: Inbox Response

Source code in src/pythonxbox/api/provider/message/__init__.py
async def get_inbox(self, max_items: int = 100, **kwargs) -> InboxResponse:
    """
    Get messages

    Returns:
        :class:`InboxResponse`: Inbox Response
    """
    url = f"{self.MSG_URL}/network/Xbox/users/me/inbox"
    params = {"maxItems": max_items}
    resp = await self.client.session.get(
        url, params=params, headers=self.HEADERS_MESSAGE, **kwargs
    )
    resp.raise_for_status()
    return InboxResponse.model_validate_json(resp.text)

get_conversation(xuid, max_items=100, **kwargs) async

Get detailed conversation info

Parameters:

Name Type Description Default
xuid str

Xuid of user having a conversation with

required

Returns:

Type Description
ConversationResponse

class:ConversationResponse: Conversation Response

Source code in src/pythonxbox/api/provider/message/__init__.py
async def get_conversation(
    self, xuid: str, max_items: int = 100, **kwargs
) -> ConversationResponse:
    """
    Get detailed conversation info

    Args:
        xuid: Xuid of user having a conversation with

    Returns:
        :class:`ConversationResponse`: Conversation Response
    """
    url = f"{self.MSG_URL}/network/Xbox/users/me/conversations/users/xuid({xuid})"
    params = {"maxItems": max_items}
    resp = await self.client.session.get(
        url, params=params, headers=self.HEADERS_MESSAGE, **kwargs
    )
    resp.raise_for_status()
    return ConversationResponse.model_validate_json(resp.text)

delete_conversation(conversation_id, horizon, **kwargs) async

Delete message

NOTE: Returns HTTP Status Code 200 on success

Parameters:

Name Type Description Default
conversation_id str

Message Id

required
horizon str

Delete horizon from get conversation response

required

Returns: True on success, False otherwise

Source code in src/pythonxbox/api/provider/message/__init__.py
async def delete_conversation(
    self, conversation_id: str, horizon: str, **kwargs
) -> bool:
    """
    Delete message

    **NOTE**: Returns HTTP Status Code **200** on success

    Args:
        conversation_id: Message Id
        horizon: Delete horizon from get conversation response

    Returns: True on success, False otherwise
    """
    url = f"{self.MSG_URL}/network/Xbox/users/me/conversations/horizon"
    post_data = {
        "conversations": [
            {
                "conversationId": conversation_id,
                "conversationType": "OneToOne",
                "horizonType": "Delete",
                "horizon": horizon,
            }
        ]
    }
    resp = await self.client.session.put(
        url, json=post_data, headers=self.HEADERS_HORIZON, **kwargs
    )
    return resp.status_code == HTTPStatus.OK

delete_message(conversation_id, message_id, **kwargs) async

Delete message

NOTE: Returns HTTP Status Code 200 on success

Parameters:

Name Type Description Default
conversation_id str

Conversation Id

required
message_id str

Message Id

required

Returns: True on success, False otherwise

Source code in src/pythonxbox/api/provider/message/__init__.py
async def delete_message(
    self, conversation_id: str, message_id: str, **kwargs
) -> bool:
    """
    Delete message

    **NOTE**: Returns HTTP Status Code **200** on success

    Args:
        conversation_id: Conversation Id
        message_id: Message Id

    Returns: True on success, False otherwise
    """
    url = f"{self.MSG_URL}/network/Xbox/users/me/conversations/{conversation_id}/messages/{message_id}"
    resp = await self.client.session.delete(
        url, headers=self.HEADERS_MESSAGE, **kwargs
    )
    return resp.status_code == HTTPStatus.OK

send_message(xuid, message_text, **kwargs) async

Send message to an xuid

Parameters:

Name Type Description Default
xuid str

Xuid

required
message_text str

Message text

required

Returns:

Type Description
SendMessageResponse

class:SendMessageResponse: Send Message Response

Source code in src/pythonxbox/api/provider/message/__init__.py
async def send_message(
    self, xuid: str, message_text: str, **kwargs
) -> SendMessageResponse:
    """
    Send message to an xuid

    Args:
        xuid: Xuid
        message_text: Message text

    Returns:
        :class:`SendMessageResponse`: Send Message Response
    """
    if len(message_text) > MESSAGE_MAX_LEN:
        raise ValueError(
            f"Message text exceeds max length of {MESSAGE_MAX_LEN} chars"
        )

    url = f"{self.MSG_URL}/network/Xbox/users/me/conversations/users/xuid({xuid})"
    post_data = {
        "parts": [
            {
                "contentType": "text",
                "version": 0,
                "text": message_text,
            }
        ]
    }
    resp = await self.client.session.post(
        url, json=post_data, headers=self.HEADERS_MESSAGE, **kwargs
    )
    resp.raise_for_status()
    return SendMessageResponse.model_validate_json(resp.text)

pythonxbox.api.provider.message.models.Part

Bases: CamelCaseModel

content_type instance-attribute

version instance-attribute

text = None class-attribute instance-attribute

unsuitable_for = None class-attribute instance-attribute

locator = None class-attribute instance-attribute

pythonxbox.api.provider.message.models.Content

Bases: CamelCaseModel

parts instance-attribute

pythonxbox.api.provider.message.models.ContentPayload

Bases: CamelCaseModel

content instance-attribute

pythonxbox.api.provider.message.models.Message

Bases: CamelCaseModel

content_payload = None class-attribute instance-attribute

timestamp instance-attribute

last_update_timestamp instance-attribute

type instance-attribute

network_id instance-attribute

conversation_type instance-attribute

conversation_id instance-attribute

owner = None class-attribute instance-attribute

sender instance-attribute

message_id instance-attribute

is_deleted instance-attribute

is_server_updated instance-attribute

pythonxbox.api.provider.message.models.Conversation

Bases: CamelCaseModel

timestamp instance-attribute

network_id instance-attribute

type instance-attribute

conversation_id instance-attribute

voice_id instance-attribute

participants instance-attribute

read_horizon instance-attribute

delete_horizon instance-attribute

is_read instance-attribute

muted instance-attribute

folder instance-attribute

last_message instance-attribute

pythonxbox.api.provider.message.models.Primary

Bases: CamelCaseModel

folder instance-attribute

total_count instance-attribute

unread_count instance-attribute

conversations instance-attribute

pythonxbox.api.provider.message.models.SafetySettings

Bases: CamelCaseModel

version instance-attribute

primary_inbox_media instance-attribute

primary_inbox_text instance-attribute

primary_inbox_url instance-attribute

secondary_inbox_media instance-attribute

secondary_inbox_text instance-attribute

secondary_inbox_url instance-attribute

can_unobscure instance-attribute

pythonxbox.api.provider.message.models.InboxResponse

Bases: CamelCaseModel

primary instance-attribute

folders instance-attribute

safety_settings instance-attribute

pythonxbox.api.provider.message.models.ConversationResponse

Bases: CamelCaseModel

timestamp instance-attribute

network_id instance-attribute

type instance-attribute

conversation_id instance-attribute

participants = None class-attribute instance-attribute

read_horizon instance-attribute

delete_horizon instance-attribute

is_read instance-attribute

muted instance-attribute

folder instance-attribute

messages = None class-attribute instance-attribute

continuation_token = None class-attribute instance-attribute

voice_id instance-attribute

voice_roster = None class-attribute instance-attribute

pythonxbox.api.provider.message.models.SendMessageResponse

Bases: CamelCaseModel

message_id instance-attribute

conversation_id instance-attribute

People - Access friendlist from own profiles and others

pythonxbox.api.provider.people.PeopleProvider(client)

Bases: RateLimitedProvider

Initialize Baseclass, set 'Accept-Language' header from client instance

Parameters:

Name Type Description Default
client (

class:XboxLiveClient): Instance of client

required
Source code in src/pythonxbox/api/provider/people/__init__.py
def __init__(self, client: "XboxLiveClient") -> None:
    """
    Initialize Baseclass, set 'Accept-Language' header from client instance

    Args:
        client (:class:`XboxLiveClient`): Instance of client
    """
    super().__init__(client)
    self._headers = {**self.HEADERS_PEOPLE}
    self._headers.update({"Accept-Language": self.client.language.locale})

SOCIAL_URL = 'https://social.xboxlive.com' class-attribute instance-attribute

HEADERS_SOCIAL = {'x-xbl-contract-version': '2'} class-attribute instance-attribute

PEOPLE_URL = 'https://peoplehub.xboxlive.com' class-attribute instance-attribute

HEADERS_PEOPLE = {'x-xbl-contract-version': '7', 'Accept-Language': 'overwrite in __init__'} class-attribute instance-attribute

SEPERATOR = ',' class-attribute instance-attribute

RATE_LIMITS = {'burst': 10, 'sustain': 30} class-attribute instance-attribute

client instance-attribute

get_friends_own(decoration_fields=None, **kwargs) async

Get friendlist of own profile

Returns:

Type Description
PeopleResponse

class:PeopleResponse: People Response

Source code in src/pythonxbox/api/provider/people/__init__.py
async def get_friends_own(
    self, decoration_fields: list[PeopleDecoration] | None = None, **kwargs
) -> PeopleResponse:
    """
    Get friendlist of own profile

    Returns:
        :class:`PeopleResponse`: People Response
    """
    if not decoration_fields:
        decoration_fields = [
            PeopleDecoration.PREFERRED_COLOR,
            PeopleDecoration.DETAIL,
            PeopleDecoration.MULTIPLAYER_SUMMARY,
            PeopleDecoration.PRESENCE_DETAIL,
        ]
    decoration = self.SEPERATOR.join(decoration_fields)

    url = f"{self.PEOPLE_URL}/users/me/people/friends/decoration/{decoration}"
    resp = await self.client.session.get(url, headers=self._headers, **kwargs)
    resp.raise_for_status()
    return PeopleResponse.model_validate_json(resp.text)

get_friends_by_xuid(xuid, decoration_fields=None, **kwargs) async

Get friendlist of own profile

Returns:

Type Description
PeopleResponse

class:PeopleResponse: People Response

Source code in src/pythonxbox/api/provider/people/__init__.py
async def get_friends_by_xuid(
    self,
    xuid: str,
    decoration_fields: list[PeopleDecoration] | None = None,
    **kwargs,
) -> PeopleResponse:
    """
    Get friendlist of own profile

    Returns:
        :class:`PeopleResponse`: People Response
    """
    if not decoration_fields:
        decoration_fields = [
            PeopleDecoration.PREFERRED_COLOR,
            PeopleDecoration.DETAIL,
            PeopleDecoration.MULTIPLAYER_SUMMARY,
            PeopleDecoration.PRESENCE_DETAIL,
        ]
    decoration = self.SEPERATOR.join(decoration_fields)

    url = f"{self.PEOPLE_URL}/users/me/people/xuids({xuid})/decoration/{decoration}"
    resp = await self.client.session.get(url, headers=self._headers, **kwargs)
    resp.raise_for_status()
    return PeopleResponse.model_validate_json(resp.text)

get_friends_own_batch(xuids, decoration_fields=None, **kwargs) async

Get friends metadata by providing a list of XUIDs

Parameters:

Name Type Description Default
xuids list[str]

List of XUIDs

required

Returns:

Type Description
PeopleResponse

class:PeopleResponse: People Response

Source code in src/pythonxbox/api/provider/people/__init__.py
async def get_friends_own_batch(
    self,
    xuids: list[str],
    decoration_fields: list[PeopleDecoration] | None = None,
    **kwargs,
) -> PeopleResponse:
    """
    Get friends metadata by providing a list of XUIDs

    Args:
        xuids: List of XUIDs

    Returns:
        :class:`PeopleResponse`: People Response
    """
    if not decoration_fields:
        decoration_fields = [
            PeopleDecoration.PREFERRED_COLOR,
            PeopleDecoration.DETAIL,
            PeopleDecoration.MULTIPLAYER_SUMMARY,
            PeopleDecoration.PRESENCE_DETAIL,
        ]
    decoration = self.SEPERATOR.join(decoration_fields)

    url = f"{self.PEOPLE_URL}/users/me/people/batch/decoration/{decoration}"
    resp = await self.client.session.post(
        url, json={"xuids": xuids}, headers=self._headers, **kwargs
    )
    resp.raise_for_status()
    return PeopleResponse.model_validate_json(resp.text)

get_friend_recommendations(decoration_fields=None, **kwargs) async

Get recommended friends

Returns:

Type Description
PeopleResponse

class:PeopleResponse: People Response

Source code in src/pythonxbox/api/provider/people/__init__.py
async def get_friend_recommendations(
    self, decoration_fields: list[PeopleDecoration] | None = None, **kwargs
) -> PeopleResponse:
    """
    Get recommended friends

    Returns:
        :class:`PeopleResponse`: People Response
    """
    if not decoration_fields:
        decoration_fields = [PeopleDecoration.DETAIL]
    decoration = self.SEPERATOR.join(decoration_fields)

    url = (
        f"{self.PEOPLE_URL}/users/me/people/recommendations/decoration/{decoration}"
    )
    resp = await self.client.session.get(url, headers=self._headers, **kwargs)
    resp.raise_for_status()
    return PeopleResponse.model_validate_json(resp.text)

get_friends_summary_own(**kwargs) async

Get friendlist summary of own profile

Returns:

Type Description
PeopleSummaryResponse

class:PeopleSummaryResponse: People Summary Response

Source code in src/pythonxbox/api/provider/people/__init__.py
async def get_friends_summary_own(self, **kwargs) -> PeopleSummaryResponse:
    """
    Get friendlist summary of own profile

    Returns:
        :class:`PeopleSummaryResponse`: People Summary Response
    """
    url = self.SOCIAL_URL + "/users/me/summary"
    resp = await self.client.session.get(
        url, headers=self.HEADERS_SOCIAL, rate_limits=self.rate_limit_read, **kwargs
    )
    resp.raise_for_status()
    return PeopleSummaryResponse.model_validate_json(resp.text)

get_friends_summary_by_xuid(xuid, **kwargs) async

Get friendlist summary of user by xuid

Parameters:

Name Type Description Default
xuid str

XUID to request summary from

required

Returns:

Type Description
PeopleSummaryResponse

class:PeopleSummaryResponse: People Summary Response

Source code in src/pythonxbox/api/provider/people/__init__.py
async def get_friends_summary_by_xuid(
    self, xuid: str, **kwargs
) -> PeopleSummaryResponse:
    """
    Get friendlist summary of user by xuid

    Args:
        xuid: XUID to request summary from

    Returns:
        :class:`PeopleSummaryResponse`: People Summary Response
    """
    url = self.SOCIAL_URL + f"/users/xuid({xuid})/summary"
    resp = await self.client.session.get(
        url, headers=self.HEADERS_SOCIAL, rate_limits=self.rate_limit_read, **kwargs
    )
    resp.raise_for_status()
    return PeopleSummaryResponse.model_validate_json(resp.text)

get_friends_summary_by_gamertag(gamertag, **kwargs) async

Get friendlist summary of user by gamertag

Parameters:

Name Type Description Default
gamertag str

Gamertag to request friendlist from

required

Returns:

Type Description
PeopleSummaryResponse

class:PeopleSummaryResponse: People Summary Response

Source code in src/pythonxbox/api/provider/people/__init__.py
async def get_friends_summary_by_gamertag(
    self, gamertag: str, **kwargs
) -> PeopleSummaryResponse:
    """
    Get friendlist summary of user by gamertag

    Args:
        gamertag: Gamertag to request friendlist from

    Returns:
        :class:`PeopleSummaryResponse`: People Summary Response
    """
    url = self.SOCIAL_URL + f"/users/gt({gamertag})/summary"
    resp = await self.client.session.get(
        url, headers=self.HEADERS_SOCIAL, rate_limits=self.rate_limit_read, **kwargs
    )
    resp.raise_for_status()
    return PeopleSummaryResponse.model_validate_json(resp.text)

pythonxbox.api.provider.people.models.PeopleDecoration

Bases: StrEnum

SUGGESTION = 'suggestion' class-attribute instance-attribute

RECENT_PLAYER = 'recentPlayer' class-attribute instance-attribute

FOLLOWER = 'follower' class-attribute instance-attribute

PREFERRED_COLOR = 'preferredColor' class-attribute instance-attribute

DETAIL = 'detail' class-attribute instance-attribute

MULTIPLAYER_SUMMARY = 'multiplayerSummary' class-attribute instance-attribute

PRESENCE_DETAIL = 'presenceDetail' class-attribute instance-attribute

TITLE_PRESENCE = 'titlePresence' class-attribute instance-attribute

TITLE_SUMMARY = 'titleSummary' class-attribute instance-attribute

PRESENCE_TITLE_IDS = 'presenceTitleIds' class-attribute instance-attribute

COMMUNITY_MANAGER_TITLES = 'communityManagerTitles' class-attribute instance-attribute

SOCIAL_MANAGER = 'socialManager' class-attribute instance-attribute

BROADCAST = 'broadcast' class-attribute instance-attribute

TOURNAMENT_SUMMARY = 'tournamentSummary' class-attribute instance-attribute

AVATAR = 'avatar' class-attribute instance-attribute

pythonxbox.api.provider.people.models.PeopleSummaryResponse

Bases: CamelCaseModel

target_following_count instance-attribute

target_follower_count instance-attribute

is_caller_following_target instance-attribute

is_target_following_caller instance-attribute

has_caller_marked_target_as_favorite instance-attribute

has_caller_marked_target_as_identity_shared instance-attribute

legacy_friend_status instance-attribute

available_people_slots = None class-attribute instance-attribute

recent_change_count = None class-attribute instance-attribute

watermark = None class-attribute instance-attribute

is_friend instance-attribute

pythonxbox.api.provider.people.models.Suggestion

Bases: PascalCaseModel

type = None class-attribute instance-attribute

priority instance-attribute

reasons = None class-attribute instance-attribute

title_id = None class-attribute instance-attribute

pythonxbox.api.provider.people.models.Recommendation

Bases: PascalCaseModel

type instance-attribute

reasons instance-attribute

pythonxbox.api.provider.people.models.SessionRef

Bases: CamelCaseModel

scid instance-attribute

template_name instance-attribute

name instance-attribute

pythonxbox.api.provider.people.models.PartyDetails

Bases: CamelCaseModel

session_ref instance-attribute

status instance-attribute

visibility instance-attribute

join_restriction instance-attribute

accepted instance-attribute

pythonxbox.api.provider.people.models.MultiplayerSummary

Bases: CamelCaseModel

in_multiplayer_session = None class-attribute instance-attribute

in_party instance-attribute

joinable_activities = Field(default_factory=list) class-attribute instance-attribute

party_details = Field(default_factory=list) class-attribute instance-attribute

pythonxbox.api.provider.people.models.RecentPlayer

Bases: CamelCaseModel

titles instance-attribute

text = None class-attribute instance-attribute

pythonxbox.api.provider.people.models.Follower

Bases: CamelCaseModel

text = None class-attribute instance-attribute

followed_date_time_utc = None class-attribute instance-attribute

pythonxbox.api.provider.people.models.PreferredColor

Bases: CamelCaseModel

primary_color = None class-attribute instance-attribute

secondary_color = None class-attribute instance-attribute

tertiary_color = None class-attribute instance-attribute

pythonxbox.api.provider.people.models.PresenceDetail

Bases: PascalCaseModel

is_broadcasting instance-attribute

device instance-attribute

device_sub_type = None class-attribute instance-attribute

gameplay_type = None class-attribute instance-attribute

presence_text instance-attribute

state instance-attribute

title_id instance-attribute

title_type = None class-attribute instance-attribute

is_primary instance-attribute

is_game instance-attribute

rich_presence_text = None class-attribute instance-attribute

pythonxbox.api.provider.people.models.TitlePresence

Bases: PascalCaseModel

is_currently_playing instance-attribute

presence_text = None class-attribute instance-attribute

title_name = None class-attribute instance-attribute

title_id = None class-attribute instance-attribute

pythonxbox.api.provider.people.models.Detail

Bases: CamelCaseModel

account_tier instance-attribute

bio = None class-attribute instance-attribute

is_verified instance-attribute

location = None class-attribute instance-attribute

tenure = None class-attribute instance-attribute

watermarks instance-attribute

blocked instance-attribute

mute instance-attribute

follower_count instance-attribute

following_count instance-attribute

has_game_pass instance-attribute

can_be_friended instance-attribute

can_be_followed instance-attribute

is_friend instance-attribute

friend_count instance-attribute

is_friend_request_received instance-attribute

is_friend_request_sent instance-attribute

is_friend_list_shared instance-attribute

is_following_caller instance-attribute

is_followed_by_caller instance-attribute

is_favorite instance-attribute

pythonxbox.api.provider.people.models.SocialManager

Bases: CamelCaseModel

title_ids instance-attribute

pages instance-attribute

pythonxbox.api.provider.people.models.Avatar

Bases: CamelCaseModel

update_time_offset = None class-attribute instance-attribute

spritesheet_metadata = None class-attribute instance-attribute

pythonxbox.api.provider.people.models.LinkedAccount

Bases: CamelCaseModel

network_name instance-attribute

display_name = None class-attribute instance-attribute

show_on_profile instance-attribute

is_family_friendly instance-attribute

pythonxbox.api.provider.people.models.Person

Bases: CamelCaseModel

xuid instance-attribute

is_favorite instance-attribute

is_following_caller instance-attribute

is_followed_by_caller instance-attribute

is_identity_shared instance-attribute

added_date_time_utc = None class-attribute instance-attribute

display_name = None class-attribute instance-attribute

real_name instance-attribute

display_pic_raw instance-attribute

show_user_as_avatar instance-attribute

gamertag instance-attribute

gamer_score instance-attribute

modern_gamertag instance-attribute

modern_gamertag_suffix instance-attribute

unique_modern_gamertag instance-attribute

xbox_one_rep instance-attribute

presence_state instance-attribute

presence_text instance-attribute

presence_devices = None class-attribute instance-attribute

is_broadcasting instance-attribute

is_cloaked = None class-attribute instance-attribute

is_quarantined instance-attribute

is_xbox_360_gamerpic instance-attribute

last_seen_date_time_utc = None class-attribute instance-attribute

suggestion = None class-attribute instance-attribute

recommendation = None class-attribute instance-attribute

search = None class-attribute instance-attribute

titleHistory = None class-attribute instance-attribute

multiplayer_summary = None class-attribute instance-attribute

recent_player = None class-attribute instance-attribute

follower = None class-attribute instance-attribute

preferred_color = None class-attribute instance-attribute

presence_details = None class-attribute instance-attribute

title_presence = None class-attribute instance-attribute

title_summaries = None class-attribute instance-attribute

presence_title_ids = None class-attribute instance-attribute

detail = None class-attribute instance-attribute

community_manager_titles = None class-attribute instance-attribute

social_manager = None class-attribute instance-attribute

broadcast = None class-attribute instance-attribute

tournament_summary = None class-attribute instance-attribute

avatar = None class-attribute instance-attribute

linked_accounts = None class-attribute instance-attribute

color_theme instance-attribute

preferred_flag instance-attribute

preferred_platforms instance-attribute

friended_date_time_utc = None class-attribute instance-attribute

is_friend instance-attribute

is_friend_request_received instance-attribute

is_friend_request_sent instance-attribute

pythonxbox.api.provider.people.models.RecommendationSummary

Bases: CamelCaseModel

friend_of_friend = None class-attribute instance-attribute

facebook_friend = None class-attribute instance-attribute

phone_contact = None class-attribute instance-attribute

follower = None class-attribute instance-attribute

VIP = None class-attribute instance-attribute

steam_friend instance-attribute

promote_suggestions instance-attribute

community_suggestion instance-attribute

pythonxbox.api.provider.people.models.FriendFinderState

Bases: CamelCaseModel

facebook_opt_in_status instance-attribute

facebook_token_status instance-attribute

phone_opt_in_status instance-attribute

phone_token_status instance-attribute

steam_opt_in_status instance-attribute

steam_token_status instance-attribute

discord_opt_in_status instance-attribute

discord_token_status instance-attribute

instagram_opt_in_status instance-attribute

instagram_token_status instance-attribute

mixer_opt_in_status instance-attribute

mixer_token_status instance-attribute

reddit_opt_in_status instance-attribute

reddit_token_status instance-attribute

twitch_opt_in_status instance-attribute

twitch_token_status instance-attribute

twitter_opt_in_status instance-attribute

twitter_token_status instance-attribute

you_tube_opt_in_status instance-attribute

you_tube_token_status instance-attribute

pythonxbox.api.provider.people.models.FriendRequestSummary

Bases: CamelCaseModel

friend_requests_received_count instance-attribute

pythonxbox.api.provider.people.models.PeopleResponse

Bases: CamelCaseModel

people instance-attribute

recommendation_summary = None class-attribute instance-attribute

friend_finder_state = None class-attribute instance-attribute

friend_request_summary = None class-attribute instance-attribute

Presence - Get online status of friends

pythonxbox.api.provider.presence.PresenceProvider(client)

Bases: BaseProvider

Source code in src/pythonxbox/api/provider/baseprovider.py
def __init__(self, client: "XboxLiveClient") -> None:
    """
    Initialize an the BaseProvider

    Args:
        client (:class:`XboxLiveClient`): Instance of XboxLiveClient
    """
    self.client = client

PRESENCE_URL = 'https://userpresence.xboxlive.com' class-attribute instance-attribute

HEADERS_PRESENCE = {'x-xbl-contract-version': '3', 'Accept': 'application/json'} class-attribute instance-attribute

get_presence(xuid, presence_level=PresenceLevel.USER, **kwargs) async

Get presence for given xuid

Parameters:

Name Type Description Default
xuid str

XUID

required
presence_level PresenceLevel

Filter level

USER

Returns:

Type Description
PresenceItem

class:PresenceItem: Presence Response

Source code in src/pythonxbox/api/provider/presence/__init__.py
async def get_presence(
    self,
    xuid: str,
    presence_level: PresenceLevel = PresenceLevel.USER,
    **kwargs,
) -> PresenceItem:
    """
    Get presence for given xuid

    Args:
        xuid: XUID
        presence_level: Filter level

    Returns:
        :class:`PresenceItem`: Presence Response
    """
    url = self.PRESENCE_URL + "/users/xuid(" + xuid + ")?level=" + presence_level

    resp = await self.client.session.get(
        url, headers=self.HEADERS_PRESENCE, **kwargs
    )
    resp.raise_for_status()
    return PresenceItem.model_validate_json(resp.text)

get_presence_batch(xuids, online_only=False, presence_level=PresenceLevel.USER, **kwargs) async

Get presence for list of xuids

Parameters:

Name Type Description Default
xuids list[str]

List of XUIDs

required
online_only bool

Only get online profiles

False
presence_level PresenceLevel

Filter level

USER

Returns: List[:class:PresenceItem]: List of presence items

Source code in src/pythonxbox/api/provider/presence/__init__.py
async def get_presence_batch(
    self,
    xuids: list[str],
    online_only: bool = False,
    presence_level: PresenceLevel = PresenceLevel.USER,
    **kwargs,
) -> list[PresenceItem]:
    """
    Get presence for list of xuids

    Args:
        xuids: List of XUIDs
        online_only: Only get online profiles
        presence_level: Filter level

    Returns: List[:class:`PresenceItem`]: List of presence items
    """
    MAX_XUIDS = 1100

    if len(xuids) > MAX_XUIDS:
        raise Exception("Xuid list length is > 1100")

    url = self.PRESENCE_URL + "/users/batch"
    post_data = {
        "users": [str(x) for x in xuids],
        "onlineOnly": online_only,
        "level": presence_level,
    }
    resp = await self.client.session.post(
        url, json=post_data, headers=self.HEADERS_PRESENCE, **kwargs
    )
    resp.raise_for_status()
    parsed = PresenceBatchResponse.model_validate_json(resp.text)
    return parsed.root

get_presence_own(presence_level=PresenceLevel.ALL, **kwargs) async

Get presence of own profile

Parameters:

Name Type Description Default
presence_level PresenceLevel

Filter level

ALL

Returns:

Type Description
PresenceItem

class:PresenceItem: Presence Response

Source code in src/pythonxbox/api/provider/presence/__init__.py
async def get_presence_own(
    self, presence_level: PresenceLevel = PresenceLevel.ALL, **kwargs
) -> PresenceItem:
    """
    Get presence of own profile

    Args:
        presence_level: Filter level

    Returns:
        :class:`PresenceItem`: Presence Response
    """
    url = self.PRESENCE_URL + "/users/me"
    params = {"level": presence_level}
    resp = await self.client.session.get(
        url, params=params, headers=self.HEADERS_PRESENCE, **kwargs
    )
    resp.raise_for_status()
    return PresenceItem.model_validate_json(resp.text)

set_presence_own(presence_state, **kwargs) async

Set presence of own profile

Parameters:

Name Type Description Default
presence_state PresenceState

State of presence

required

Returns:

Type Description
bool

True on success, False otherwise

Source code in src/pythonxbox/api/provider/presence/__init__.py
async def set_presence_own(self, presence_state: PresenceState, **kwargs) -> bool:
    """
    Set presence of own profile

    Args:
        presence_state: State of presence

    Returns:
        `True` on success, `False` otherwise
    """
    url = self.PRESENCE_URL + f"/users/xuid({self.client.xuid})/state"
    data = {"state": presence_state.value}
    resp = await self.client.session.put(
        url, json=data, headers=self.HEADERS_PRESENCE, **kwargs
    )
    return resp.status_code == HTTPStatus.OK

pythonxbox.api.provider.presence.models.PresenceLevel

Bases: StrEnum

USER = 'user' class-attribute instance-attribute

DEVICE = 'device' class-attribute instance-attribute

TITLE = 'title' class-attribute instance-attribute

ALL = 'all' class-attribute instance-attribute

pythonxbox.api.provider.presence.models.PresenceState

Bases: StrEnum

ACTIVE = 'Active' class-attribute instance-attribute

CLOAKED = 'Cloaked' class-attribute instance-attribute

pythonxbox.api.provider.presence.models.LastSeen

Bases: CamelCaseModel

device_type instance-attribute

title_id = None class-attribute instance-attribute

title_name instance-attribute

timestamp instance-attribute

pythonxbox.api.provider.presence.models.ActivityRecord

Bases: CamelCaseModel

richPresence = None class-attribute instance-attribute

media = None class-attribute instance-attribute

pythonxbox.api.provider.presence.models.TitleRecord

Bases: CamelCaseModel

id = None class-attribute instance-attribute

name = None class-attribute instance-attribute

activity = None class-attribute instance-attribute

lastModified = None class-attribute instance-attribute

placement = None class-attribute instance-attribute

state = None class-attribute instance-attribute

pythonxbox.api.provider.presence.models.DeviceRecord

Bases: CamelCaseModel

titles = None class-attribute instance-attribute

type = None class-attribute instance-attribute

pythonxbox.api.provider.presence.models.PresenceItem

Bases: CamelCaseModel

xuid instance-attribute

state instance-attribute

last_seen = None class-attribute instance-attribute

devices = None class-attribute instance-attribute

pythonxbox.api.provider.presence.models.PresenceBatchResponse

Bases: RootModel[list[PresenceItem]], CamelCaseModel

root instance-attribute

Profile

Get Userprofiles by XUID or Gamertag

pythonxbox.api.provider.profile.ProfileProvider(client)

Bases: RateLimitedProvider

Source code in src/pythonxbox/api/provider/ratelimitedprovider.py
def __init__(self, client: "XboxLiveClient") -> None:
    """
    Initialize Baseclass

    Args:
        client (:class:`XboxLiveClient`): Instance of XboxLiveClient
    """
    super().__init__(client)

    # Check that RATE_LIMITS set defined in the child class
    if hasattr(self, "RATE_LIMITS"):
        # Note: we cannot check (type(self.RATE_LIMITS) == dict) as the type hints have already defined it as such
        if "burst" and "sustain" in self.RATE_LIMITS:
            # We have the required keys, attempt to parse.
            # (type-checking for the values is performed in __parse_rate_limit_key)
            self.__handle_rate_limit_setup()
        else:
            raise XboxException(
                "RATE_LIMITS object missing required keys 'burst', 'sustain'"
            )
    else:
        raise XboxException(
            "RateLimitedProvider as parent class but RATE_LIMITS not set!"
        )

PROFILE_URL = 'https://profile.xboxlive.com' class-attribute instance-attribute

HEADERS_PROFILE = {'x-xbl-contract-version': '3'} class-attribute instance-attribute

SEPARATOR = ',' class-attribute instance-attribute

RATE_LIMITS = {'burst': 10, 'sustain': 30} class-attribute instance-attribute

get_profiles(xuid_list, **kwargs) async

Get profile info for list of xuids

Parameters:

Name Type Description Default
xuid_list list

List of xuids

required

Returns:

Type Description
ProfileResponse

class:ProfileResponse: Profile Response

Source code in src/pythonxbox/api/provider/profile/__init__.py
async def get_profiles(self, xuid_list: list[str], **kwargs) -> ProfileResponse:
    """
    Get profile info for list of xuids

    Args:
        xuid_list (list): List of xuids

    Returns:
        :class:`ProfileResponse`: Profile Response
    """
    post_data = {
        "settings": [
            ProfileSettings.GAME_DISPLAY_NAME,
            ProfileSettings.APP_DISPLAY_NAME,
            ProfileSettings.APP_DISPLAYPIC_RAW,
            ProfileSettings.GAMERSCORE,
            ProfileSettings.GAMERTAG,
            ProfileSettings.GAME_DISPLAYPIC_RAW,
            ProfileSettings.ACCOUNT_TIER,
            ProfileSettings.TENURE_LEVEL,
            ProfileSettings.XBOX_ONE_REP,
            ProfileSettings.PREFERRED_COLOR,
            ProfileSettings.LOCATION,
            ProfileSettings.BIOGRAPHY,
            ProfileSettings.WATERMARKS,
            ProfileSettings.REAL_NAME,
        ],
        "userIds": xuid_list,
    }
    url = self.PROFILE_URL + "/users/batch/profile/settings"
    resp = await self.client.session.post(
        url,
        json=post_data,
        headers=self.HEADERS_PROFILE,
        rate_limits=self.rate_limit_read,
        **kwargs,
    )
    resp.raise_for_status()
    return ProfileResponse.model_validate_json(resp.text)

get_profile_by_xuid(target_xuid, **kwargs) async

Get Userprofile by xuid

Parameters:

Name Type Description Default
target_xuid str

XUID to get profile for

required

Returns:

Type Description
ProfileResponse

class:ProfileResponse: Profile Response

Source code in src/pythonxbox/api/provider/profile/__init__.py
async def get_profile_by_xuid(self, target_xuid: str, **kwargs) -> ProfileResponse:
    """
    Get Userprofile by xuid

    Args:
        target_xuid: XUID to get profile for

    Returns:
        :class:`ProfileResponse`: Profile Response
    """
    url = self.PROFILE_URL + f"/users/xuid({target_xuid})/profile/settings"
    params = {
        "settings": self.SEPARATOR.join(
            [
                ProfileSettings.GAMERTAG,
                ProfileSettings.MODERN_GAMERTAG,
                ProfileSettings.MODERN_GAMERTAG_SUFFIX,
                ProfileSettings.UNIQUE_MODERN_GAMERTAG,
                ProfileSettings.REAL_NAME_OVERRIDE,
                ProfileSettings.BIOGRAPHY,
                ProfileSettings.LOCATION,
                ProfileSettings.GAMERSCORE,
                ProfileSettings.GAME_DISPLAYPIC_RAW,
                ProfileSettings.TENURE_LEVEL,
                ProfileSettings.ACCOUNT_TIER,
                ProfileSettings.XBOX_ONE_REP,
                ProfileSettings.PREFERRED_COLOR,
                ProfileSettings.WATERMARKS,
                ProfileSettings.IS_QUARANTINED,
            ]
        )
    }
    resp = await self.client.session.get(
        url,
        params=params,
        headers=self.HEADERS_PROFILE,
        rate_limits=self.rate_limit_read,
        **kwargs,
    )
    resp.raise_for_status()
    return ProfileResponse.model_validate_json(resp.text)

get_profile_by_gamertag(gamertag, **kwargs) async

Get Userprofile by gamertag

Parameters:

Name Type Description Default
gamertag str

Gamertag to get profile for

required

Returns:

Type Description
ProfileResponse

class:ProfileResponse: Profile Response

Source code in src/pythonxbox/api/provider/profile/__init__.py
async def get_profile_by_gamertag(self, gamertag: str, **kwargs) -> ProfileResponse:
    """
    Get Userprofile by gamertag

    Args:
        gamertag: Gamertag to get profile for

    Returns:
        :class:`ProfileResponse`: Profile Response
    """
    url = self.PROFILE_URL + f"/users/gt({gamertag})/profile/settings"
    params = {
        "settings": self.SEPARATOR.join(
            [
                ProfileSettings.GAMERTAG,
                ProfileSettings.MODERN_GAMERTAG,
                ProfileSettings.MODERN_GAMERTAG_SUFFIX,
                ProfileSettings.UNIQUE_MODERN_GAMERTAG,
                ProfileSettings.REAL_NAME_OVERRIDE,
                ProfileSettings.BIOGRAPHY,
                ProfileSettings.LOCATION,
                ProfileSettings.GAMERSCORE,
                ProfileSettings.GAME_DISPLAYPIC_RAW,
                ProfileSettings.TENURE_LEVEL,
                ProfileSettings.ACCOUNT_TIER,
                ProfileSettings.XBOX_ONE_REP,
                ProfileSettings.PREFERRED_COLOR,
                ProfileSettings.WATERMARKS,
                ProfileSettings.IS_QUARANTINED,
            ]
        )
    }
    resp = await self.client.session.get(
        url,
        params=params,
        headers=self.HEADERS_PROFILE,
        rate_limits=self.rate_limit_read,
        **kwargs,
    )
    resp.raise_for_status()
    return ProfileResponse.model_validate_json(resp.text)

pythonxbox.api.provider.profile.models.ProfileSettings

Bases: StrEnum

Profile settings, used as parameter for Profile API

GAME_DISPLAY_NAME = 'GameDisplayName' class-attribute instance-attribute

APP_DISPLAY_NAME = 'AppDisplayName' class-attribute instance-attribute

APP_DISPLAYPIC_RAW = 'AppDisplayPicRaw' class-attribute instance-attribute

GAME_DISPLAYPIC_RAW = 'GameDisplayPicRaw' class-attribute instance-attribute

PUBLIC_GAMERPIC = 'PublicGamerpic' class-attribute instance-attribute

SHOW_USER_AS_AVATAR = 'ShowUserAsAvatar' class-attribute instance-attribute

GAMERSCORE = 'Gamerscore' class-attribute instance-attribute

GAMERTAG = 'Gamertag' class-attribute instance-attribute

MODERN_GAMERTAG = 'ModernGamertag' class-attribute instance-attribute

MODERN_GAMERTAG_SUFFIX = 'ModernGamertagSuffix' class-attribute instance-attribute

UNIQUE_MODERN_GAMERTAG = 'UniqueModernGamertag' class-attribute instance-attribute

ACCOUNT_TIER = 'AccountTier' class-attribute instance-attribute

TENURE_LEVEL = 'TenureLevel' class-attribute instance-attribute

XBOX_ONE_REP = 'XboxOneRep' class-attribute instance-attribute

PREFERRED_COLOR = 'PreferredColor' class-attribute instance-attribute

LOCATION = 'Location' class-attribute instance-attribute

BIOGRAPHY = 'Bio' class-attribute instance-attribute

WATERMARKS = 'Watermarks' class-attribute instance-attribute

REAL_NAME = 'RealName' class-attribute instance-attribute

REAL_NAME_OVERRIDE = 'RealNameOverride' class-attribute instance-attribute

IS_QUARANTINED = 'IsQuarantined' class-attribute instance-attribute

pythonxbox.api.provider.profile.models.Setting

Bases: CamelCaseModel

id instance-attribute

value instance-attribute

pythonxbox.api.provider.profile.models.ProfileUser

Bases: CamelCaseModel

id instance-attribute

host_id instance-attribute

settings instance-attribute

is_sponsored_user instance-attribute

pythonxbox.api.provider.profile.models.ProfileResponse

Bases: CamelCaseModel

profile_users instance-attribute

Screenshots - Get screenshot info

pythonxbox.api.provider.screenshots.ScreenshotsProvider(client)

Bases: BaseProvider

Source code in src/pythonxbox/api/provider/baseprovider.py
def __init__(self, client: "XboxLiveClient") -> None:
    """
    Initialize an the BaseProvider

    Args:
        client (:class:`XboxLiveClient`): Instance of XboxLiveClient
    """
    self.client = client

SCREENSHOTS_METADATA_URL = 'https://screenshotsmetadata.xboxlive.com' class-attribute instance-attribute

HEADERS_SCREENSHOTS_METADATA = {'x-xbl-contract-version': '5'} class-attribute instance-attribute

get_recent_community_screenshots_by_title_id(title_id, **kwargs) async

Get recent community screenshots by Title Id

Parameters:

Name Type Description Default
title_id str

Title Id to get screenshots for

required

Returns:

Type Description
ScreenshotResponse

class:ScreenshotResponse: Screenshot Response

Source code in src/pythonxbox/api/provider/screenshots/__init__.py
async def get_recent_community_screenshots_by_title_id(
    self, title_id: str, **kwargs
) -> ScreenshotResponse:
    """
    Get recent community screenshots by Title Id

    Args:
        title_id: Title Id to get screenshots for

    Returns:
        :class:`ScreenshotResponse`: Screenshot Response
    """
    url = self.SCREENSHOTS_METADATA_URL + f"/public/titles/{title_id}/screenshots"
    params = {"qualifier": "created"}
    resp = await self.client.session.get(
        url, params=params, headers=self.HEADERS_SCREENSHOTS_METADATA, **kwargs
    )
    resp.raise_for_status()
    return ScreenshotResponse.model_validate_json(resp.text)

get_recent_own_screenshots(title_id=None, skip_items=0, max_items=25, **kwargs) async

Get own recent screenshots, optionally filter for title Id

Parameters:

Name Type Description Default
title_id str | None

Title ID to filter

None
skip_items int

Item count to skip

0
max_items int

Maximum item count to load

25

Returns:

Type Description
ScreenshotResponse

class:ScreenshotResponse: Screenshot Response

Source code in src/pythonxbox/api/provider/screenshots/__init__.py
async def get_recent_own_screenshots(
    self,
    title_id: str | None = None,
    skip_items: int = 0,
    max_items: int = 25,
    **kwargs,
) -> ScreenshotResponse:
    """
    Get own recent screenshots, optionally filter for title Id

    Args:
        title_id: Title ID to filter
        skip_items: Item count to skip
        max_items: Maximum item count to load

    Returns:
        :class:`ScreenshotResponse`: Screenshot Response
    """
    url = self.SCREENSHOTS_METADATA_URL + "/users/me"
    if title_id:
        url += f"/titles/{title_id}"
    url += "/screenshots"

    params = {"skipItems": skip_items, "maxItems": max_items}
    resp = await self.client.session.get(
        url, params=params, headers=self.HEADERS_SCREENSHOTS_METADATA, **kwargs
    )
    resp.raise_for_status()
    return ScreenshotResponse.model_validate_json(resp.text)

get_recent_screenshots_by_xuid(xuid, title_id=None, skip_items=0, max_items=25, **kwargs) async

Get recent screenshots by XUID, optionally filter for title Id

Parameters:

Name Type Description Default
xuid str

XUID of user to get screenshots from

required
title_id str | None

Optional title id filter

None
skip_items int

Item count to skip

0
max_items int

Maximum item count to load

25

Returns:

Type Description
ScreenshotResponse

class:ScreenshotResponse: Screenshot Response

Source code in src/pythonxbox/api/provider/screenshots/__init__.py
async def get_recent_screenshots_by_xuid(
    self,
    xuid: str,
    title_id: str | None = None,
    skip_items: int = 0,
    max_items: int = 25,
    **kwargs,
) -> ScreenshotResponse:
    """
    Get recent screenshots by XUID, optionally filter for title Id

    Args:
        xuid: XUID of user to get screenshots from
        title_id: Optional title id filter
        skip_items: Item count to skip
        max_items: Maximum item count to load

    Returns:
        :class:`ScreenshotResponse`: Screenshot Response
    """
    url = self.SCREENSHOTS_METADATA_URL + f"/users/xuid({xuid})"
    if title_id:
        url += f"/titles/{title_id}"
    url += "/screenshots"

    params = {"skipItems": skip_items, "maxItems": max_items}
    resp = await self.client.session.get(
        url, params=params, headers=self.HEADERS_SCREENSHOTS_METADATA, **kwargs
    )
    resp.raise_for_status()
    return ScreenshotResponse.model_validate_json(resp.text)

get_saved_community_screenshots_by_title_id(title_id, **kwargs) async

Get saved community screenshots by Title Id

Parameters:

Name Type Description Default
title_id str

Title Id to get screenshots for

required

Returns:

Type Description
ScreenshotResponse

class:ScreenshotResponse: Screenshot Response

Source code in src/pythonxbox/api/provider/screenshots/__init__.py
async def get_saved_community_screenshots_by_title_id(
    self, title_id: str, **kwargs
) -> ScreenshotResponse:
    """
    Get saved community screenshots by Title Id

    Args:
        title_id: Title Id to get screenshots for

    Returns:
        :class:`ScreenshotResponse`: Screenshot Response
    """
    url = f"{self.SCREENSHOTS_METADATA_URL}/public/titles/{title_id}/screenshots/saved"
    params = {"qualifier": "created"}
    resp = await self.client.session.get(
        url, params=params, headers=self.HEADERS_SCREENSHOTS_METADATA, **kwargs
    )
    resp.raise_for_status()
    return ScreenshotResponse.model_validate_json(resp.text)

get_saved_own_screenshots(title_id=None, skip_items=0, max_items=25, **kwargs) async

Get own saved screenshots, optionally filter for title Id an

Parameters:

Name Type Description Default
title_id str | None

Optional Title ID to filter

None
skip_items int

Item count to skip

0
max_items int

Maximum item count to load

25

Returns:

Type Description
ScreenshotResponse

class:ScreenshotResponse: Screenshot Response

Source code in src/pythonxbox/api/provider/screenshots/__init__.py
async def get_saved_own_screenshots(
    self,
    title_id: str | None = None,
    skip_items: int = 0,
    max_items: int = 25,
    **kwargs,
) -> ScreenshotResponse:
    """
    Get own saved screenshots, optionally filter for title Id an

    Args:
        title_id: Optional Title ID to filter
        skip_items: Item count to skip
        max_items: Maximum item count to load

    Returns:
        :class:`ScreenshotResponse`: Screenshot Response
    """
    url = self.SCREENSHOTS_METADATA_URL + "/users/me"
    if title_id:
        url += f"/titles/{title_id}"
    url += "/screenshots/saved"

    params = {"skipItems": skip_items, "maxItems": max_items}
    resp = await self.client.session.get(
        url, params=params, headers=self.HEADERS_SCREENSHOTS_METADATA, **kwargs
    )
    resp.raise_for_status()
    return ScreenshotResponse.model_validate_json(resp.text)

get_saved_screenshots_by_xuid(xuid, title_id=None, skip_items=0, max_items=25, **kwargs) async

Get saved screenshots by XUID, optionally filter for title Id

Parameters:

Name Type Description Default
xuid str

XUID of user to get screenshots from

required
title_id str | None

Optional title id filter

None
skip_items int

Item count to skip

0
max_items int

Maximum item count to load

25

Returns:

Type Description
ScreenshotResponse

class:ScreenshotResponse: Screenshot Response

Source code in src/pythonxbox/api/provider/screenshots/__init__.py
async def get_saved_screenshots_by_xuid(
    self,
    xuid: str,
    title_id: str | None = None,
    skip_items: int = 0,
    max_items: int = 25,
    **kwargs,
) -> ScreenshotResponse:
    """
    Get saved screenshots by XUID, optionally filter for title Id

    Args:
        xuid: XUID of user to get screenshots from
        title_id: Optional title id filter
        skip_items: Item count to skip
        max_items: Maximum item count to load

    Returns:
        :class:`ScreenshotResponse`: Screenshot Response
    """
    url = self.SCREENSHOTS_METADATA_URL + f"/users/xuid({xuid})"
    if title_id:
        url += f"/titles/{title_id}"
    url += "/screenshots/saved"

    params = {"skipItems": skip_items, "maxItems": max_items}
    resp = await self.client.session.get(
        url, params=params, headers=self.HEADERS_SCREENSHOTS_METADATA, **kwargs
    )
    resp.raise_for_status()
    return ScreenshotResponse.model_validate_json(resp.text)

pythonxbox.api.provider.screenshots.models.Thumbnail

Bases: CamelCaseModel

uri instance-attribute

file_size instance-attribute

thumbnail_type instance-attribute

pythonxbox.api.provider.screenshots.models.ScreenshotUri

Bases: CamelCaseModel

uri instance-attribute

file_size instance-attribute

uri_type instance-attribute

expiration instance-attribute

pythonxbox.api.provider.screenshots.models.Screenshot

Bases: CamelCaseModel

screenshot_id instance-attribute

resolution_height instance-attribute

resolution_width instance-attribute

state instance-attribute

date_published instance-attribute

date_taken instance-attribute

last_modified instance-attribute

user_caption instance-attribute

type instance-attribute

scid instance-attribute

title_id instance-attribute

rating instance-attribute

rating_count instance-attribute

views instance-attribute

title_data instance-attribute

system_properties instance-attribute

saved_by_user instance-attribute

achievement_id instance-attribute

greatest_moment_id = None class-attribute instance-attribute

thumbnails instance-attribute

screenshot_uris instance-attribute

xuid instance-attribute

screenshot_name instance-attribute

title_name instance-attribute

screenshot_locale instance-attribute

screenshot_content_attributes instance-attribute

device_type instance-attribute

pythonxbox.api.provider.screenshots.models.PagingInfo

Bases: CamelCaseModel

continuation_token = None class-attribute instance-attribute

pythonxbox.api.provider.screenshots.models.ScreenshotResponse

Bases: CamelCaseModel

screenshots instance-attribute

paging_info instance-attribute

SmartGlass - Control Registered Devices

pythonxbox.api.provider.smartglass.SmartglassProvider(client)

Bases: BaseProvider

Initialize Baseclass, create smartglass session id

Args: Instance of XBL client

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
def __init__(self, client: "XboxLiveClient") -> None:
    """
    Initialize Baseclass, create smartglass session id

    Args: Instance of XBL client
    """
    super().__init__(client)
    self._smartglass_session_id = str(uuid4())

SG_URL = 'https://xccs.xboxlive.com' class-attribute instance-attribute

HEADERS_SG = {'x-xbl-contract-version': '4', 'skillplatform': 'RemoteManagement'} class-attribute instance-attribute

get_console_list(include_storage_devices=True, **kwargs) async

Get Console list

Parameters:

Name Type Description Default
include_storage_devices bool

Include a list of storage devices in the response

True

Returns: Console List

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def get_console_list(
    self, include_storage_devices: bool = True, **kwargs
) -> SmartglassConsoleList:
    """
    Get Console list

    Args:
        include_storage_devices: Include a list of storage devices in the response

    Returns: Console List
    """
    params = {
        "queryCurrentDevice": "false",
        "includeStorageDevices": str(include_storage_devices).lower(),
    }
    resp = await self._fetch_list("devices", params, **kwargs)
    return SmartglassConsoleList.model_validate_json(resp.text)

get_installed_apps(device_id=None, **kwargs) async

Get Installed Apps

Parameters:

Name Type Description Default
device_id str | None

ID of console (from console list)

None

Returns: Installed Apps

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def get_installed_apps(
    self, device_id: str | None = None, **kwargs
) -> InstalledPackagesList:
    """
    Get Installed Apps

    Args:
        device_id: ID of console (from console list)

    Returns: Installed Apps
    """
    params = {}
    if device_id:
        params["deviceId"] = device_id
    resp = await self._fetch_list("installedApps", params, **kwargs)
    return InstalledPackagesList.model_validate_json(resp.text)

get_storage_devices(device_id, **kwargs) async

Get Installed Apps

Parameters:

Name Type Description Default
device_id str

ID of console (from console list)

required

Returns: Storage Devices list

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def get_storage_devices(self, device_id: str, **kwargs) -> StorageDevicesList:
    """
    Get Installed Apps

    Args:
        device_id: ID of console (from console list)

    Returns: Storage Devices list
    """
    params = {"deviceId": device_id}
    resp = await self._fetch_list("storageDevices", params, **kwargs)
    return StorageDevicesList.model_validate_json(resp.text)

get_console_status(device_id, **kwargs) async

Get Console Status

Parameters:

Name Type Description Default
device_id str

ID of console (from console list)

required

Returns: Console Status

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def get_console_status(
    self, device_id: str, **kwargs
) -> SmartglassConsoleStatus:
    """
    Get Console Status

    Args:
        device_id: ID of console (from console list)

    Returns: Console Status
    """
    url = f"{self.SG_URL}/consoles/{device_id}"
    resp = await self.client.session.get(url, headers=self.HEADERS_SG, **kwargs)
    resp.raise_for_status()
    return SmartglassConsoleStatus.model_validate_json(resp.text)

get_op_status(device_id, op_id, **kwargs) async

Get Operation Status

Parameters:

Name Type Description Default
device_id str

ID of console (from console list)

required
op_id str

Operation ID (from previous command)

required

Returns: Operation Status

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def get_op_status(
    self, device_id: str, op_id: str, **kwargs
) -> OperationStatusResponse:
    """
    Get Operation Status

    Args:
        device_id: ID of console (from console list)
        op_id: Operation ID (from previous command)

    Returns: Operation Status
    """
    url = f"{self.SG_URL}/opStatus"
    headers = {
        "x-xbl-contract-version": "3",
        "x-xbl-opId": op_id,
        "x-xbl-deviceId": device_id,
    }
    resp = await self.client.session.get(url, headers=headers, **kwargs)
    resp.raise_for_status()
    return OperationStatusResponse.model_validate_json(resp.text)

wake_up(device_id, **kwargs) async

Wake Up Console

Parameters:

Name Type Description Default
device_id str

ID of console (from console list)

required

Returns: Command Response

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def wake_up(self, device_id: str, **kwargs) -> CommandResponse:
    """
    Wake Up Console

    Args:
        device_id: ID of console (from console list)

    Returns: Command Response
    """
    return await self._send_one_shot_command(device_id, "Power", "WakeUp", **kwargs)

turn_off(device_id, **kwargs) async

Turn Off Console

Parameters:

Name Type Description Default
device_id str

ID of console (from console list)

required

Returns: Command Response

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def turn_off(self, device_id: str, **kwargs) -> CommandResponse:
    """
    Turn Off Console

    Args:
        device_id: ID of console (from console list)

    Returns: Command Response
    """
    return await self._send_one_shot_command(
        device_id, "Power", "TurnOff", **kwargs
    )

reboot(device_id, **kwargs) async

Reboot Console

Parameters:

Name Type Description Default
device_id str

ID of console (from console list)

required

Returns: Command Response

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def reboot(self, device_id: str, **kwargs) -> CommandResponse:
    """
    Reboot Console

    Args:
        device_id: ID of console (from console list)

    Returns: Command Response
    """
    return await self._send_one_shot_command(device_id, "Power", "Reboot", **kwargs)

mute(device_id, **kwargs) async

Mute

Parameters:

Name Type Description Default
device_id str

ID of console (from console list)

required

Returns: Command Response

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def mute(self, device_id: str, **kwargs) -> CommandResponse:
    """
    Mute

    Args:
        device_id: ID of console (from console list)

    Returns: Command Response
    """
    return await self._send_one_shot_command(device_id, "Audio", "Mute", **kwargs)

unmute(device_id, **kwargs) async

Unmute

Parameters:

Name Type Description Default
device_id str

ID of console (from console list)

required

Returns: Command Response

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def unmute(self, device_id: str, **kwargs) -> CommandResponse:
    """
    Unmute

    Args:
        device_id: ID of console (from console list)

    Returns: Command Response
    """
    return await self._send_one_shot_command(device_id, "Audio", "Unmute", **kwargs)

volume(device_id, direction, amount=1, **kwargs) async

Adjust Volume

Parameters:

Name Type Description Default
device_id str

ID of console (from console list)

required

Returns: Command Response

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def volume(
    self, device_id: str, direction: VolumeDirection, amount: int = 1, **kwargs
) -> CommandResponse:
    """
    Adjust Volume

    Args:
        device_id: ID of console (from console list)

    Returns: Command Response
    """
    params = [{"direction": direction.value, "amount": str(amount)}]
    return await self._send_one_shot_command(
        device_id, "Audio", "Volume", params, **kwargs
    )

play(device_id, **kwargs) async

Play (media controls)

Parameters:

Name Type Description Default
device_id str

ID of console (from console list)

required

Returns: Command Response

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def play(self, device_id: str, **kwargs) -> CommandResponse:
    """
    Play (media controls)

    Args:
        device_id: ID of console (from console list)

    Returns: Command Response
    """
    return await self._send_one_shot_command(device_id, "Media", "Play", **kwargs)

pause(device_id, **kwargs) async

Pause (media controls)

Parameters:

Name Type Description Default
device_id str

ID of console (from console list)

required

Returns: Command Response

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def pause(self, device_id: str, **kwargs) -> CommandResponse:
    """
    Pause (media controls)

    Args:
        device_id: ID of console (from console list)

    Returns: Command Response
    """
    return await self._send_one_shot_command(device_id, "Media", "Pause", **kwargs)

previous(device_id, **kwargs) async

Previous (media controls)

Parameters:

Name Type Description Default
device_id str

ID of console (from console list)

required

Returns: Command Response

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def previous(self, device_id: str, **kwargs) -> CommandResponse:
    """
    Previous (media controls)

    Args:
        device_id: ID of console (from console list)

    Returns: Command Response
    """
    return await self._send_one_shot_command(
        device_id, "Media", "Previous", **kwargs
    )

next(device_id, **kwargs) async

Next (media controls)

Parameters:

Name Type Description Default
device_id str

ID of console (from console list)

required

Returns: Command Response

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def next(self, device_id: str, **kwargs) -> CommandResponse:
    """
    Next (media controls)

    Args:
        device_id: ID of console (from console list)

    Returns: Command Response
    """
    return await self._send_one_shot_command(device_id, "Media", "Next", **kwargs)

go_home(device_id, **kwargs) async

Go Home

Parameters:

Name Type Description Default
device_id str

ID of console (from console list)

required

Returns: Command Response

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def go_home(self, device_id: str, **kwargs) -> CommandResponse:
    """
    Go Home

    Args:
        device_id: ID of console (from console list)

    Returns: Command Response
    """
    return await self._send_one_shot_command(device_id, "Shell", "GoHome", **kwargs)

go_back(device_id, **kwargs) async

Go Back

Parameters:

Name Type Description Default
device_id str

ID of console (from console list)

required

Returns:

Type Description
CommandResponse

class:SmartglassConsoleStatus: Command Response

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def go_back(self, device_id: str, **kwargs) -> CommandResponse:
    """
    Go Back

    Args:
        device_id: ID of console (from console list)

    Returns:
        :class:`SmartglassConsoleStatus`: Command Response
    """
    return await self._send_one_shot_command(device_id, "Shell", "GoBack", **kwargs)

show_guide_tab(device_id, tab=GuideTab.Guide, **kwargs) async

Show Guide Tab

Parameters:

Name Type Description Default
device_id str

ID of console (from console list)

required

Returns: Command Response

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def show_guide_tab(
    self, device_id: str, tab: GuideTab = GuideTab.Guide, **kwargs
) -> CommandResponse:
    """
    Show Guide Tab

    Args:
        device_id: ID of console (from console list)

    Returns: Command Response
    """
    params = [{"tabName": tab.value}]
    return await self._send_one_shot_command(
        device_id, "Shell", "ShowGuideTab", params, **kwargs
    )

press_button(device_id, button, **kwargs) async

Press Button

Parameters:

Name Type Description Default
device_id str

ID of console (from console list)

required

Returns: Command Response

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def press_button(
    self, device_id: str, button: InputKeyType, **kwargs
) -> CommandResponse:
    """
    Press Button

    Args:
        device_id: ID of console (from console list)

    Returns: Command Response
    """
    params = [{"keyType": button.value}]
    return await self._send_one_shot_command(
        device_id, "Shell", "InjectKey", params, **kwargs
    )

insert_text(device_id, text, **kwargs) async

Insert Text

Parameters:

Name Type Description Default
device_id str

ID of console (from console list)

required

Returns: Command Response

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def insert_text(self, device_id: str, text: str, **kwargs) -> CommandResponse:
    """
    Insert Text

    Args:
        device_id: ID of console (from console list)

    Returns: Command Response
    """
    params = [{"replacementString": text}]
    return await self._send_one_shot_command(
        device_id, "Shell", "InjectString", params, **kwargs
    )

launch_app(device_id, one_store_product_id, **kwargs) async

Launch Application

Parameters:

Name Type Description Default
device_id str

ID of console (from console list)

required
one_store_product_id str

OneStoreProductID for the app to launch

required

Returns: Command Response

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def launch_app(
    self, device_id: str, one_store_product_id: str, **kwargs
) -> CommandResponse:
    """
    Launch Application

    Args:
        device_id: ID of console (from console list)
        one_store_product_id: OneStoreProductID for the app to launch

    Returns: Command Response
    """
    params = [{"oneStoreProductId": one_store_product_id}]
    return await self._send_one_shot_command(
        device_id,
        "Shell",
        "ActivateApplicationWithOneStoreProductId",
        params,
        **kwargs,
    )

show_tv_guide(device_id, **kwargs) async

Show TV Guide

Parameters:

Name Type Description Default
device_id str

ID of console (from console list)

required

Returns: Command Response

Source code in src/pythonxbox/api/provider/smartglass/__init__.py
async def show_tv_guide(self, device_id: str, **kwargs) -> CommandResponse:
    """
    Show TV Guide

    Args:
        device_id: ID of console (from console list)

    Returns: Command Response
    """
    return await self._send_one_shot_command(device_id, "TV", "ShowGuide", **kwargs)

pythonxbox.api.provider.smartglass.models.ConsoleType

Bases: StrEnum

XboxOne = 'XboxOne' class-attribute instance-attribute

XboxOneS = 'XboxOneS' class-attribute instance-attribute

XboxOneSDigital = 'XboxOneSDigital' class-attribute instance-attribute

XboxOneX = 'XboxOneX' class-attribute instance-attribute

XboxSeriesS = 'XboxSeriesS' class-attribute instance-attribute

XboxSeriesX = 'XboxSeriesX' class-attribute instance-attribute

pythonxbox.api.provider.smartglass.models.PowerState

Bases: StrEnum

Unknown = 'Unknown' class-attribute instance-attribute

On = 'On' class-attribute instance-attribute

Off = 'Off' class-attribute instance-attribute

ConnectedStandby = 'ConnectedStandby' class-attribute instance-attribute

SystemUpdate = 'SystemUpdate' class-attribute instance-attribute

pythonxbox.api.provider.smartglass.models.PlaybackState

Bases: StrEnum

Unknown = 'Unknown' class-attribute instance-attribute

Playing = 'Playing' class-attribute instance-attribute

Paused = 'Paused' class-attribute instance-attribute

Stopped = 'Stopped' class-attribute instance-attribute

pythonxbox.api.provider.smartglass.models.ErrorCode

Bases: StrEnum

OK = 'OK' class-attribute instance-attribute

CurrentConsoleNotFound = 'CurrentConsoleNotFound' class-attribute instance-attribute

RemoteManagementDisabled = 'RemoteManagementDisabled' class-attribute instance-attribute

XboxDataNotFound = 'XboxDataNotFound' class-attribute instance-attribute

XboxNotPaired = 'XboxNotPaired' class-attribute instance-attribute

pythonxbox.api.provider.smartglass.models.OpStatus

Bases: StrEnum

Paused = 'Paused' class-attribute instance-attribute

OffConsoleError = 'OffConsoleError' class-attribute instance-attribute

Pending = 'Pending' class-attribute instance-attribute

TimedOut = 'TimedOut' class-attribute instance-attribute

Error = 'Error' class-attribute instance-attribute

Succeeded = 'Succeeded' class-attribute instance-attribute

pythonxbox.api.provider.smartglass.models.SmartglassApiStatus

Bases: CamelCaseModel

error_code instance-attribute

error_message = None class-attribute instance-attribute

pythonxbox.api.provider.smartglass.models.StorageDevice

Bases: CamelCaseModel

storage_device_id instance-attribute

storage_device_name instance-attribute

is_default instance-attribute

total_space_bytes instance-attribute

free_space_bytes instance-attribute

pythonxbox.api.provider.smartglass.models.SmartglassConsole

Bases: CamelCaseModel

id instance-attribute

name instance-attribute

console_type instance-attribute

power_state instance-attribute

console_streaming_enabled instance-attribute

digital_assistant_remote_control_enabled instance-attribute

remote_management_enabled instance-attribute

storage_devices = None class-attribute instance-attribute

pythonxbox.api.provider.smartglass.models.SmartglassConsoleList

Bases: CamelCaseModel

agent_user_id = None class-attribute instance-attribute

result instance-attribute

status instance-attribute

pythonxbox.api.provider.smartglass.models.SmartglassConsoleStatus

Bases: CamelCaseModel

console_streaming_enabled instance-attribute

digital_assistant_remote_control_enabled instance-attribute

remote_management_enabled instance-attribute

focus_app_aumid instance-attribute

is_tv_configured instance-attribute

login_state = None class-attribute instance-attribute

playback_state instance-attribute

power_state instance-attribute

storage_devices = None class-attribute instance-attribute

status instance-attribute

pythonxbox.api.provider.smartglass.models.InstalledPackage

Bases: CamelCaseModel

one_store_product_id = None class-attribute instance-attribute

title_id instance-attribute

aumid = None class-attribute instance-attribute

last_active_time = None class-attribute instance-attribute

is_game instance-attribute

name = None class-attribute instance-attribute

content_type instance-attribute

instance_id instance-attribute

storage_device_id instance-attribute

unique_id instance-attribute

legacy_product_id = None class-attribute instance-attribute

version instance-attribute

size_in_bytes instance-attribute

install_time instance-attribute

update_time = None class-attribute instance-attribute

parent_id = None class-attribute instance-attribute

pythonxbox.api.provider.smartglass.models.InstalledPackagesList

Bases: CamelCaseModel

result instance-attribute

status instance-attribute

agent_user_id = None class-attribute instance-attribute

pythonxbox.api.provider.smartglass.models.StorageDevicesList

Bases: CamelCaseModel

device_id instance-attribute

result instance-attribute

status instance-attribute

pythonxbox.api.provider.smartglass.models.OpStatusNode

Bases: CamelCaseModel

operation_status instance-attribute

op_id instance-attribute

originating_session_id instance-attribute

command instance-attribute

succeeded instance-attribute

console_status_code = None class-attribute instance-attribute

xccs_error_code = None class-attribute instance-attribute

h_result = None class-attribute instance-attribute

message = None class-attribute instance-attribute

pythonxbox.api.provider.smartglass.models.OperationStatusResponse

Bases: CamelCaseModel

op_status_list instance-attribute

status instance-attribute

pythonxbox.api.provider.smartglass.models.CommandDestination

Bases: CamelCaseModel

id instance-attribute

name instance-attribute

power_state instance-attribute

remote_management_enabled instance-attribute

console_streaming_enabled instance-attribute

console_type instance-attribute

wireless_warning = None class-attribute instance-attribute

out_of_home_warning = None class-attribute instance-attribute

pythonxbox.api.provider.smartglass.models.CommandResponse

Bases: CamelCaseModel

result = None class-attribute instance-attribute

ui_text = None class-attribute instance-attribute

destination instance-attribute

user_info = None class-attribute instance-attribute

op_id instance-attribute

status instance-attribute

pythonxbox.api.provider.smartglass.models.VolumeDirection

Bases: StrEnum

Up = 'Up' class-attribute instance-attribute

Down = 'Down' class-attribute instance-attribute

pythonxbox.api.provider.smartglass.models.InputKeyType

Bases: StrEnum

Guide = 'Guide' class-attribute instance-attribute

Menu = 'Menu' class-attribute instance-attribute

View = 'View' class-attribute instance-attribute

A = 'A' class-attribute instance-attribute

B = 'B' class-attribute instance-attribute

X = 'X' class-attribute instance-attribute

Y = 'Y' class-attribute instance-attribute

Up = 'Up' class-attribute instance-attribute

Down = 'Down' class-attribute instance-attribute

Left = 'Left' class-attribute instance-attribute

Right = 'Right' class-attribute instance-attribute

Nexus = 'Nexus' class-attribute instance-attribute

pythonxbox.api.provider.smartglass.models.GuideTab

Bases: StrEnum

Guide = 'Guide' class-attribute instance-attribute

Titlehub - Get Title history and info

pythonxbox.api.provider.titlehub.TitlehubProvider(client)

Bases: BaseProvider

Initialize Baseclass, set 'Accept-Language' header from client instance

Parameters:

Name Type Description Default
client (

class:XboxLiveClient): Instance of client

required
Source code in src/pythonxbox/api/provider/titlehub/__init__.py
def __init__(self, client: "XboxLiveClient") -> None:
    """
    Initialize Baseclass, set 'Accept-Language' header from client instance

    Args:
        client (:class:`XboxLiveClient`): Instance of client
    """
    super().__init__(client)
    self._headers = {
        "x-xbl-contract-version": "2",
        "x-xbl-client-name": "XboxApp",
        "x-xbl-client-type": "UWA",
        "x-xbl-client-version": "39.39.22001.0",
        "Accept-Language": self.client.language.locale,
    }

TITLEHUB_URL = 'https://titlehub.xboxlive.com' class-attribute instance-attribute

SEPARATOR = ',' class-attribute instance-attribute

get_title_history(xuid, fields=None, max_items=5, **kwargs) async

Get recently played titles

Parameters:

Name Type Description Default
xuid str

Xuid

required
fields list[TitleFields] | None

List of titlefield

None
max_items int | None

Maximum items

5

Returns:

Type Description
TitleHubResponse

class:TitleHubResponse: Title Hub Response

Source code in src/pythonxbox/api/provider/titlehub/__init__.py
async def get_title_history(
    self,
    xuid: str,
    fields: list[TitleFields] | None = None,
    max_items: int | None = 5,
    **kwargs,
) -> TitleHubResponse:
    """
    Get recently played titles

    Args:
        xuid: Xuid
        fields: List of titlefield
        max_items: Maximum items

    Returns:
        :class:`TitleHubResponse`: Title Hub Response
    """
    if not fields:
        fields = [
            TitleFields.ACHIEVEMENT,
            TitleFields.IMAGE,
            TitleFields.SERVICE_CONFIG_ID,
        ]
    fields = self.SEPARATOR.join(fields)

    url = f"{self.TITLEHUB_URL}/users/xuid({xuid})/titles/titlehistory/decoration/{fields}"
    params = {"maxItems": max_items}
    resp = await self.client.session.get(
        url, params=params, headers=self._headers, **kwargs
    )
    resp.raise_for_status()
    return TitleHubResponse.model_validate_json(resp.text)

get_title_info(title_id, fields=None, **kwargs) async

Get info for specific title

Parameters:

Name Type Description Default
title_id str

Title Id

required
fields list[TitleFields] | None

List of title fields

None

Returns:

Type Description
TitleHubResponse

class:TitleHubResponse: Title Hub Response

Source code in src/pythonxbox/api/provider/titlehub/__init__.py
async def get_title_info(
    self, title_id: str, fields: list[TitleFields] | None = None, **kwargs
) -> TitleHubResponse:
    """
    Get info for specific title

    Args:
        title_id: Title Id
        fields: List of title fields

    Returns:
        :class:`TitleHubResponse`: Title Hub Response
    """
    return await self._get_title_info(f"titleid({title_id})", fields, **kwargs)

get_title_info_by_pfn(pfn, fields=None, **kwargs) async

Get info for specific title by PFN

Parameters:

Name Type Description Default
pfn str

Package family name

required
fields list[TitleFields] | None

List of title fields

None

Returns:

Type Description
TitleHubResponse

class:TitleHubResponse: Title Hub Response

Source code in src/pythonxbox/api/provider/titlehub/__init__.py
async def get_title_info_by_pfn(
    self, pfn: str, fields: list[TitleFields] | None = None, **kwargs
) -> TitleHubResponse:
    """
    Get info for specific title by PFN

    Args:
        pfn: Package family name
        fields: List of title fields

    Returns:
        :class:`TitleHubResponse`: Title Hub Response
    """
    return await self._get_title_info(f"pfn({pfn})", fields, **kwargs)

get_titles_batch(pfns, fields=None, **kwargs) async

Get Title info via PFN ids

Parameters:

Name Type Description Default
pfns list[str]

List of Package family names (e.g. 'Microsoft.XboxApp_8wekyb3d8bbwe')

required
fields list[TitleFields] | None

List of title fields

None

Returns:

Type Description
TitleHubResponse

class:TitleHubResponse: Title Hub Response

Source code in src/pythonxbox/api/provider/titlehub/__init__.py
async def get_titles_batch(
    self, pfns: list[str], fields: list[TitleFields] | None = None, **kwargs
) -> TitleHubResponse:
    """
    Get Title info via PFN ids

    Args:
        pfns: List of Package family names (e.g. 'Microsoft.XboxApp_8wekyb3d8bbwe')
        fields: List of title fields

    Returns:
        :class:`TitleHubResponse`: Title Hub Response
    """
    if not fields:
        fields = [
            TitleFields.ACHIEVEMENT,
            TitleFields.DETAIL,
            TitleFields.IMAGE,
            TitleFields.SERVICE_CONFIG_ID,
        ]
    fields = self.SEPARATOR.join(fields)

    url = self.TITLEHUB_URL + f"/titles/batch/decoration/{fields}"
    post_data = {"pfns": pfns, "windowsPhoneProductIds": []}
    resp = await self.client.session.post(
        url, json=post_data, headers=self._headers, **kwargs
    )
    resp.raise_for_status()
    return TitleHubResponse.model_validate_json(resp.text)

pythonxbox.api.provider.titlehub.models.TitleFields

Bases: StrEnum

SERVICE_CONFIG_ID = 'scid' class-attribute instance-attribute

ACHIEVEMENT = 'achievement' class-attribute instance-attribute

STATS = 'stats' class-attribute instance-attribute

GAME_PASS = 'gamepass' class-attribute instance-attribute

IMAGE = 'image' class-attribute instance-attribute

DETAIL = 'detail' class-attribute instance-attribute

FRIENDS_WHO_PLAYED = 'friendswhoplayed' class-attribute instance-attribute

ALTERNATE_TITLE_ID = 'alternateTitleId' class-attribute instance-attribute

PRODUCT_ID = 'productId' class-attribute instance-attribute

CONTENT_BOARD = 'contentBoard' class-attribute instance-attribute

pythonxbox.api.provider.titlehub.models.Achievement

Bases: CamelCaseModel

current_achievements instance-attribute

total_achievements instance-attribute

current_gamerscore instance-attribute

total_gamerscore instance-attribute

progress_percentage instance-attribute

source_version instance-attribute

pythonxbox.api.provider.titlehub.models.Stats

Bases: CamelCaseModel

source_version instance-attribute

pythonxbox.api.provider.titlehub.models.GamePass

Bases: CamelCaseModel

is_game_pass instance-attribute

pythonxbox.api.provider.titlehub.models.Image

Bases: CamelCaseModel

url instance-attribute

type instance-attribute

pythonxbox.api.provider.titlehub.models.TitleHistory

Bases: CamelCaseModel

last_time_played instance-attribute

visible instance-attribute

can_hide instance-attribute

pythonxbox.api.provider.titlehub.models.Attribute

Bases: CamelCaseModel

applicable_platforms = None class-attribute instance-attribute

maximum = None class-attribute instance-attribute

minimum = None class-attribute instance-attribute

name instance-attribute

pythonxbox.api.provider.titlehub.models.Availability

Bases: PascalCaseModel

actions instance-attribute

availability_id instance-attribute

platforms instance-attribute

sku_id instance-attribute

pythonxbox.api.provider.titlehub.models.Detail

Bases: CamelCaseModel

attributes instance-attribute

availabilities instance-attribute

capabilities instance-attribute

description instance-attribute

developer_name = None class-attribute instance-attribute

genres = None class-attribute instance-attribute

publisher_name instance-attribute

min_age = None class-attribute instance-attribute

release_date = None class-attribute instance-attribute

short_description = None class-attribute instance-attribute

vui_display_name = None class-attribute instance-attribute

xbox_live_gold_required instance-attribute

pythonxbox.api.provider.titlehub.models.Title

Bases: CamelCaseModel

title_id instance-attribute

pfn = None class-attribute instance-attribute

bing_id = None class-attribute instance-attribute

service_config_id = None class-attribute instance-attribute

windows_phone_product_id = None class-attribute instance-attribute

name instance-attribute

type instance-attribute

devices instance-attribute

display_image instance-attribute

media_item_type instance-attribute

modern_title_id = None class-attribute instance-attribute

is_bundle instance-attribute

achievement = None class-attribute instance-attribute

stats = None class-attribute instance-attribute

game_pass = None class-attribute instance-attribute

images = None class-attribute instance-attribute

title_history = None class-attribute instance-attribute

detail = None class-attribute instance-attribute

friends_who_played = None class-attribute instance-attribute

alternate_title_ids = None class-attribute instance-attribute

content_boards = None class-attribute instance-attribute

xbox_live_tier = None class-attribute instance-attribute

is_streamable = None class-attribute instance-attribute

pythonxbox.api.provider.titlehub.models.TitleHubResponse

Bases: CamelCaseModel

xuid = None class-attribute instance-attribute

titles instance-attribute

Usersearch - Search for gamertags / userprofiles

pythonxbox.api.provider.usersearch.UserSearchProvider(client)

Bases: BaseProvider

Source code in src/pythonxbox/api/provider/baseprovider.py
def __init__(self, client: "XboxLiveClient") -> None:
    """
    Initialize an the BaseProvider

    Args:
        client (:class:`XboxLiveClient`): Instance of XboxLiveClient
    """
    self.client = client

USERSEARCH_URL = 'https://usersearch.xboxlive.com' class-attribute instance-attribute

Get userprofiles for search query

Parameters:

Name Type Description Default
query str

Search query

required

Returns:

Type Description
UserSearchResponse

class:UserSearchResponse: User Search Response

Source code in src/pythonxbox/api/provider/usersearch/__init__.py
async def get_live_search(self, query: str, **kwargs) -> UserSearchResponse:
    """
    Get userprofiles for search query

    Args:
        query: Search query

    Returns:
        :class:`UserSearchResponse`: User Search Response
    """
    url = self.USERSEARCH_URL + "/suggest"
    params = {"q": query}
    resp = await self.client.session.get(
        url, params=params, headers=self.HEADERS_USER_SEARCH, **kwargs
    )
    resp.raise_for_status()
    return UserSearchResponse.model_validate_json(resp.text)

pythonxbox.api.provider.usersearch.models.UserDetail

Bases: CamelCaseModel

id instance-attribute

gamertag instance-attribute

display_pic_uri instance-attribute

score instance-attribute

pythonxbox.api.provider.usersearch.models.UserResult

Bases: CamelCaseModel

text instance-attribute

result instance-attribute

pythonxbox.api.provider.usersearch.models.UserSearchResponse

Bases: CamelCaseModel

results instance-attribute

Userstats - Get game statistics

pythonxbox.api.provider.userstats.UserStatsProvider(client)

Bases: RateLimitedProvider

Source code in src/pythonxbox/api/provider/ratelimitedprovider.py
def __init__(self, client: "XboxLiveClient") -> None:
    """
    Initialize Baseclass

    Args:
        client (:class:`XboxLiveClient`): Instance of XboxLiveClient
    """
    super().__init__(client)

    # Check that RATE_LIMITS set defined in the child class
    if hasattr(self, "RATE_LIMITS"):
        # Note: we cannot check (type(self.RATE_LIMITS) == dict) as the type hints have already defined it as such
        if "burst" and "sustain" in self.RATE_LIMITS:
            # We have the required keys, attempt to parse.
            # (type-checking for the values is performed in __parse_rate_limit_key)
            self.__handle_rate_limit_setup()
        else:
            raise XboxException(
                "RATE_LIMITS object missing required keys 'burst', 'sustain'"
            )
    else:
        raise XboxException(
            "RateLimitedProvider as parent class but RATE_LIMITS not set!"
        )

USERSTATS_URL = 'https://userstats.xboxlive.com' class-attribute instance-attribute

HEADERS_USERSTATS = {'x-xbl-contract-version': '2'} class-attribute instance-attribute

HEADERS_USERSTATS_WITH_METADATA = {'x-xbl-contract-version': '3'} class-attribute instance-attribute

SEPERATOR = ',' class-attribute instance-attribute

RATE_LIMITS = {'burst': 100, 'sustain': 300} class-attribute instance-attribute

get_stats(xuid, service_config_id, stats_fields=None, **kwargs) async

Get userstats

Parameters:

Name Type Description Default
xuid str

Xbox User Id

required
service_config_id str

Service Config Id of Game (scid)

required
stats_fields list[GeneralStatsField] | None

List of stats fields to acquire

None

Returns:

Type Description
UserStatsResponse

class:UserStatsResponse: User Stats Response

Source code in src/pythonxbox/api/provider/userstats/__init__.py
async def get_stats(
    self,
    xuid: str,
    service_config_id: str,
    stats_fields: list[GeneralStatsField] | None = None,
    **kwargs,
) -> UserStatsResponse:
    """
    Get userstats

    Args:
        xuid: Xbox User Id
        service_config_id: Service Config Id of Game (scid)
        stats_fields: List of stats fields to acquire

    Returns:
        :class:`UserStatsResponse`: User Stats Response
    """
    if not stats_fields:
        stats_fields = [GeneralStatsField.MINUTES_PLAYED]
    stats = self.SEPERATOR.join(stats_fields)

    url = f"{self.USERSTATS_URL}/users/xuid({xuid})/scids/{service_config_id}/stats/{stats}"
    resp = await self.client.session.get(
        url,
        headers=self.HEADERS_USERSTATS,
        rate_limits=self.rate_limit_read,
        **kwargs,
    )
    resp.raise_for_status()
    return UserStatsResponse.model_validate_json(resp.text)

get_stats_with_metadata(xuid, service_config_id, stats_fields=None, **kwargs) async

Get userstats including metadata for each stat (if available)

Parameters:

Name Type Description Default
xuid str

Xbox User Id

required
service_config_id str

Service Config Id of Game (scid)

required
stats_fields list[GeneralStatsField] | None

List of stats fields to acquire

None

Returns:

Type Description
UserStatsResponse

class:UserStatsResponse: User Stats Response

Source code in src/pythonxbox/api/provider/userstats/__init__.py
async def get_stats_with_metadata(
    self,
    xuid: str,
    service_config_id: str,
    stats_fields: list[GeneralStatsField] | None = None,
    **kwargs,
) -> UserStatsResponse:
    """
    Get userstats including metadata for each stat (if available)

    Args:
        xuid: Xbox User Id
        service_config_id: Service Config Id of Game (scid)
        stats_fields: List of stats fields to acquire

    Returns:
        :class:`UserStatsResponse`: User Stats Response
    """
    if not stats_fields:
        stats_fields = [GeneralStatsField.MINUTES_PLAYED]
    stats = self.SEPERATOR.join(stats_fields)

    url = f"{self.USERSTATS_URL}/users/xuid({xuid})/scids/{service_config_id}/stats/{stats}"
    params = {"include": "valuemetadata"}
    resp = await self.client.session.get(
        url,
        params=params,
        headers=self.HEADERS_USERSTATS_WITH_METADATA,
        rate_limits=self.rate_limit_read,
        **kwargs,
    )
    resp.raise_for_status()
    return UserStatsResponse.model_validate_json(resp.text)

get_stats_batch(xuids, title_id, stats_fields=None, **kwargs) async

Get userstats in batch mode

Parameters:

Name Type Description Default
xuids list[str]

List of XUIDs to get stats for

required
title_id str

Game Title Id

required
stats_fields list[GeneralStatsField] | None

List of stats fields to acquire

None

Returns:

Type Description
UserStatsResponse

class:UserStatsResponse: User Stats Response

Source code in src/pythonxbox/api/provider/userstats/__init__.py
async def get_stats_batch(
    self,
    xuids: list[str],
    title_id: str,
    stats_fields: list[GeneralStatsField] | None = None,
    **kwargs,
) -> UserStatsResponse:
    """
    Get userstats in batch mode

    Args:
        xuids: List of XUIDs to get stats for
        title_id: Game Title Id
        stats_fields: List of stats fields to acquire

    Returns:
        :class:`UserStatsResponse`: User Stats Response
    """
    if not stats_fields:
        stats_fields = [GeneralStatsField.MINUTES_PLAYED]

    url = self.USERSTATS_URL + "/batch"
    post_data = {
        "arrangebyfield": "xuid",
        "groups": [{"name": "Hero", "titleId": title_id}],
        "stats": [{"name": stat, "titleId": title_id} for stat in stats_fields],
        "xuids": xuids,
    }
    resp = await self.client.session.post(
        url,
        json=post_data,
        headers=self.HEADERS_USERSTATS,
        rate_limits=self.rate_limit_read,
        **kwargs,
    )
    resp.raise_for_status()
    return UserStatsResponse.model_validate_json(resp.text)

get_stats_batch_by_scid(xuids, service_config_id, stats_fields=None, **kwargs) async

Get userstats in batch mode, via scid

Parameters:

Name Type Description Default
xuids list[str]

List of XUIDs to get stats for

required
service_config_id str

Service Config Id of Game (scid)

required
stats_fields list[GeneralStatsField] | None

List of stats fields to acquire

None

Returns:

Type Description
UserStatsResponse

class:UserStatsResponse: User Stats Response

Source code in src/pythonxbox/api/provider/userstats/__init__.py
async def get_stats_batch_by_scid(
    self,
    xuids: list[str],
    service_config_id: str,
    stats_fields: list[GeneralStatsField] | None = None,
    **kwargs,
) -> UserStatsResponse:
    """
    Get userstats in batch mode, via scid

    Args:
        xuids: List of XUIDs to get stats for
        service_config_id: Service Config Id of Game (scid)
        stats_fields: List of stats fields to acquire

    Returns:
        :class:`UserStatsResponse`: User Stats Response
    """
    if not stats_fields:
        stats_fields = [GeneralStatsField.MINUTES_PLAYED]

    url = self.USERSTATS_URL + "/batch"

    post_data = {
        "arrangebyfield": "xuid",
        "groups": [{"name": "Hero", "scid": service_config_id}],
        "stats": [
            {"name": stat, "scid": service_config_id} for stat in stats_fields
        ],
        "xuids": xuids,
    }
    resp = await self.client.session.post(
        url,
        json=post_data,
        headers=self.HEADERS_USERSTATS,
        rate_limits=self.rate_limit_read,
        **kwargs,
    )
    resp.raise_for_status()
    return UserStatsResponse.model_validate_json(resp.text)

pythonxbox.api.provider.userstats.models.GeneralStatsField

MINUTES_PLAYED = 'MinutesPlayed' class-attribute instance-attribute

pythonxbox.api.provider.userstats.models.GroupProperties

Bases: PascalCaseModel

ordinal = None class-attribute instance-attribute

sort_order = None class-attribute instance-attribute

display_name = None class-attribute instance-attribute

display_format = None class-attribute instance-attribute

display_semantic = None class-attribute instance-attribute

pythonxbox.api.provider.userstats.models.Properties

Bases: PascalCaseModel

display_name = None class-attribute instance-attribute

pythonxbox.api.provider.userstats.models.Stat

Bases: FlatCaseModel

group_properties = None class-attribute instance-attribute

xuid instance-attribute

scid instance-attribute

name instance-attribute

type instance-attribute

value instance-attribute

properties instance-attribute

pythonxbox.api.provider.userstats.models.StatListsCollectionItem

Bases: FlatCaseModel

arrange_by_field instance-attribute

arrange_by_field_id instance-attribute

stats instance-attribute

pythonxbox.api.provider.userstats.models.Group

Bases: FlatCaseModel

name instance-attribute

title_id = None class-attribute instance-attribute

statlistscollection instance-attribute

pythonxbox.api.provider.userstats.models.UserStatsResponse

Bases: FlatCaseModel

groups = None class-attribute instance-attribute

statlistscollection instance-attribute

RateLimitedProvider

Subclassed by providers with rate limit support

pythonxbox.api.provider.ratelimitedprovider.RateLimitedProvider(client)

Bases: BaseProvider

Initialize Baseclass

Parameters:

Name Type Description Default
client (

class:XboxLiveClient): Instance of XboxLiveClient

required
Source code in src/pythonxbox/api/provider/ratelimitedprovider.py
def __init__(self, client: "XboxLiveClient") -> None:
    """
    Initialize Baseclass

    Args:
        client (:class:`XboxLiveClient`): Instance of XboxLiveClient
    """
    super().__init__(client)

    # Check that RATE_LIMITS set defined in the child class
    if hasattr(self, "RATE_LIMITS"):
        # Note: we cannot check (type(self.RATE_LIMITS) == dict) as the type hints have already defined it as such
        if "burst" and "sustain" in self.RATE_LIMITS:
            # We have the required keys, attempt to parse.
            # (type-checking for the values is performed in __parse_rate_limit_key)
            self.__handle_rate_limit_setup()
        else:
            raise XboxException(
                "RATE_LIMITS object missing required keys 'burst', 'sustain'"
            )
    else:
        raise XboxException(
            "RateLimitedProvider as parent class but RATE_LIMITS not set!"
        )

RATE_LIMITS instance-attribute

__handle_rate_limit_setup()

Source code in src/pythonxbox/api/provider/ratelimitedprovider.py
def __handle_rate_limit_setup(self) -> None:
    # Retrieve burst and sustain from the dict
    burst_key = self.RATE_LIMITS["burst"]
    sustain_key = self.RATE_LIMITS["sustain"]

    # Parse the rate limit dict values
    burst_rate_limits = self.__parse_rate_limit_key(burst_key, TimePeriod.BURST)
    sustain_rate_limits = self.__parse_rate_limit_key(
        sustain_key, TimePeriod.SUSTAIN
    )

    # Instanciate CombinedRateLimits for read and write respectively
    self.rate_limit_read = CombinedRateLimit(
        burst_rate_limits, sustain_rate_limits, type=LimitType.READ
    )
    self.rate_limit_write = CombinedRateLimit(
        burst_rate_limits, sustain_rate_limits, type=LimitType.WRITE
    )

__parse_rate_limit_key(key, period)

Source code in src/pythonxbox/api/provider/ratelimitedprovider.py
def __parse_rate_limit_key(
    self, key: int | dict[str, int], period: TimePeriod
) -> ParsedRateLimit:
    if isinstance(key, int) and not isinstance(key, bool):
        # bool is a subclass of int, hence the explicit check
        return ParsedRateLimit(read=key, write=key, period=period)
    if isinstance(key, dict):
        # TODO: schema here?
        # Since the key-value pairs match we can just pass the dict to the model
        return ParsedRateLimit(**key, period=period)

    raise XboxException(
        "RATE_LIMITS value types not recognised. Must be one of 'int, 'dict'."
    )

Authentication Manager

Authenticate with Windows Live Server and Xbox Live.

pythonxbox.authentication.manager.log = logging.getLogger('authentication') module-attribute

pythonxbox.authentication.manager.DEFAULT_SCOPES = ['Xboxlive.signin', 'Xboxlive.offline_access'] module-attribute

pythonxbox.authentication.manager.AuthenticationManager(client_session, client_id, client_secret, redirect_uri, scopes=None)

Source code in src/pythonxbox/authentication/manager.py
def __init__(
    self,
    client_session: SignedSession | httpx.AsyncClient,
    client_id: str,
    client_secret: str,
    redirect_uri: str,
    scopes: list[str] | None = None,
) -> None:
    self.session = client_session
    self._client_id = client_id
    self._client_secret = client_secret
    self._redirect_uri = redirect_uri
    self._scopes = scopes or DEFAULT_SCOPES

oauth = None class-attribute instance-attribute

user_token = None class-attribute instance-attribute

xsts_token = None class-attribute instance-attribute

session = client_session instance-attribute

generate_authorization_url(state=None)

Generate Windows Live Authorization URL.

Source code in src/pythonxbox/authentication/manager.py
def generate_authorization_url(self, state: str | None = None) -> str:
    """Generate Windows Live Authorization URL."""
    query_params = {
        "client_id": self._client_id,
        "response_type": "code",
        "approval_prompt": "auto",
        "scope": " ".join(self._scopes),
        "redirect_uri": self._redirect_uri,
    }

    if state:
        query_params["state"] = state

    return str(
        httpx.URL(
            "https://login.live.com/oauth20_authorize.srf", params=query_params
        )
    )

request_tokens(authorization_code) async

Request all tokens.

Source code in src/pythonxbox/authentication/manager.py
async def request_tokens(self, authorization_code: str) -> None:
    """Request all tokens."""
    self.oauth = await self.request_oauth_token(authorization_code)
    self.user_token = await self.request_user_token()
    self.xsts_token = await self.request_xsts_token()

refresh_tokens() async

Refresh all tokens.

Source code in src/pythonxbox/authentication/manager.py
async def refresh_tokens(self) -> None:
    """Refresh all tokens."""
    if not (self.oauth and self.oauth.is_valid()):
        self.oauth = await self.refresh_oauth_token()
    if not (self.user_token and self.user_token.is_valid()):
        self.user_token = await self.request_user_token()
    if not (self.xsts_token and self.xsts_token.is_valid()):
        self.xsts_token = await self.request_xsts_token()

request_oauth_token(authorization_code) async

Request OAuth2 token.

Source code in src/pythonxbox/authentication/manager.py
async def request_oauth_token(self, authorization_code: str) -> OAuth2TokenResponse:
    """Request OAuth2 token."""
    return await self._oauth2_token_request(
        {
            "grant_type": "authorization_code",
            "code": authorization_code,
            "scope": " ".join(self._scopes),
            "redirect_uri": self._redirect_uri,
        }
    )

refresh_oauth_token() async

Refresh OAuth2 token.

Source code in src/pythonxbox/authentication/manager.py
async def refresh_oauth_token(self) -> OAuth2TokenResponse:
    """Refresh OAuth2 token."""
    return await self._oauth2_token_request(
        {
            "grant_type": "refresh_token",
            "scope": " ".join(self._scopes),
            "refresh_token": self.oauth.refresh_token,
        }
    )

request_user_token(relying_party='http://auth.xboxlive.com', use_compact_ticket=False) async

Authenticate via access token and receive user token.

Source code in src/pythonxbox/authentication/manager.py
async def request_user_token(
    self,
    relying_party: str = "http://auth.xboxlive.com",
    use_compact_ticket: bool = False,
) -> XAUResponse:
    """Authenticate via access token and receive user token."""
    url = "https://user.auth.xboxlive.com/user/authenticate"
    headers = {"x-xbl-contract-version": "1"}
    data = {
        "RelyingParty": relying_party,
        "TokenType": "JWT",
        "Properties": {
            "AuthMethod": "RPS",
            "SiteName": "user.auth.xboxlive.com",
            "RpsTicket": self.oauth.access_token
            if use_compact_ticket
            else f"d={self.oauth.access_token}",
        },
    }

    resp = await self.session.post(url, json=data, headers=headers)
    resp.raise_for_status()
    return XAUResponse.model_validate_json(resp.text)

request_xsts_token(relying_party='http://xboxlive.com') async

Authorize via user token and receive final X token.

Source code in src/pythonxbox/authentication/manager.py
async def request_xsts_token(
    self, relying_party: str = "http://xboxlive.com"
) -> XSTSResponse:
    """Authorize via user token and receive final X token."""
    url = "https://xsts.auth.xboxlive.com/xsts/authorize"
    headers = {"x-xbl-contract-version": "1"}
    data = {
        "RelyingParty": relying_party,
        "TokenType": "JWT",
        "Properties": {
            "UserTokens": [self.user_token.token],
            "SandboxId": "RETAIL",
        },
    }

    resp = await self.session.post(url, json=data, headers=headers)
    if resp.status_code == HTTPStatus.UNAUTHORIZED:  # if unauthorized
        msg = (
            "Failed to authorize you! Your password or username may be wrong or"
            " you are trying to use child account (< 18 years old)"
        )
        raise AuthenticationException(msg)
    resp.raise_for_status()
    return XSTSResponse.model_validate_json(resp.text)

Xbox Authentication Library

Authenticate with Windows Live Server and Xbox Live (used by mobile Xbox Apps)

pythonxbox.authentication.xal.log = logging.getLogger('xal.authentication') module-attribute

pythonxbox.authentication.xal.APP_PARAMS_XBOX_BETA_APP = XalAppParameters(app_id='000000004415494b', title_id='177887386', redirect_uri='ms-xal-000000004415494b://auth') module-attribute

pythonxbox.authentication.xal.APP_PARAMS_XBOX_APP = XalAppParameters(app_id='000000004c12ae6f', title_id='328178078', redirect_uri='ms-xal-000000004c12ae6f://auth') module-attribute

pythonxbox.authentication.xal.APP_PARAMS_GAMEPASS = XalAppParameters(app_id='000000004c20a908', title_id='1016898439', redirect_uri='ms-xal-000000004c20a908://auth') module-attribute

pythonxbox.authentication.xal.APP_PARAMS_GAMEPASS_BETA = XalAppParameters(app_id='000000004c20a908', title_id='1016898439', redirect_uri='ms-xal-public-beta-000000004c20a908://auth') module-attribute

pythonxbox.authentication.xal.APP_PARAMS_FAMILY_SETTINGS = XalAppParameters(app_id='00000000482C8F49', title_id='1618633878', redirect_uri='https://login.live.com/oauth20_desktop.srf') module-attribute

pythonxbox.authentication.xal.CLIENT_PARAMS_IOS = XalClientParameters(user_agent='XAL iOS 2021.11.20211021.000', device_type='iOS', client_version='15.6.1', query_display='ios_phone') module-attribute

pythonxbox.authentication.xal.CLIENT_PARAMS_ANDROID = XalClientParameters(user_agent='XAL Android 2020.07.20200714.000', device_type='Android', client_version='8.0.0', query_display='android_phone') module-attribute

pythonxbox.authentication.xal.XALManager(session, device_id, app_params, client_params)

Source code in src/pythonxbox/authentication/xal.py
def __init__(
    self,
    session: SignedSession,
    device_id: uuid.UUID,
    app_params: XalAppParameters,
    client_params: XalClientParameters,
) -> None:
    self.session = session
    self.device_id = device_id
    self.app_params = app_params
    self.client_params = client_params
    self.cv = CorrelationVector()

session = session instance-attribute

device_id = device_id instance-attribute

app_params = app_params instance-attribute

client_params = client_params instance-attribute

cv = CorrelationVector() instance-attribute

get_title_endpoints(session) async staticmethod

Source code in src/pythonxbox/authentication/xal.py
@staticmethod
async def get_title_endpoints(session: httpx.AsyncClient) -> TitleEndpointsResponse:
    url = "https://title.mgt.xboxlive.com/titles/default/endpoints"
    headers = {"x-xbl-contract-version": "1"}
    params = {"type": 1}
    resp = await session.get(url, headers=headers, params=params)
    resp.raise_for_status()
    return TitleEndpointsResponse.model_validate_json(resp.text)

request_device_token() async

Source code in src/pythonxbox/authentication/xal.py
async def request_device_token(self) -> XADResponse:
    # Proof of possession: https://tools.ietf.org/html/rfc7800

    device_id = str(self.device_id)

    if self.client_params.device_type.lower() == "android":
        # {decf45e4-945d-4379-b708-d4ee92c12d99}
        device_id = f"{{{device_id}}}"
    else:
        # iOSs
        # DECF45E4-945D-4379-B708-D4EE92C12D99
        device_id = device_id.upper()

    url = "https://device.auth.xboxlive.com/device/authenticate"
    headers = {"x-xbl-contract-version": "1", "MS-CV": self.cv.get_value()}
    data = {
        "RelyingParty": "http://auth.xboxlive.com",
        "TokenType": "JWT",
        "Properties": {
            "AuthMethod": "ProofOfPossession",
            "Id": device_id,
            "DeviceType": self.client_params.device_type,
            "Version": self.client_params.client_version,
            "ProofKey": self.session.request_signer.proof_field,
        },
    }

    resp = await self.session.send_signed("POST", url, headers=headers, json=data)
    resp.raise_for_status()
    return XADResponse.model_validate_json(resp.text)

__oauth20_token_endpoint(json_body) async

Source code in src/pythonxbox/authentication/xal.py
async def __oauth20_token_endpoint(self, json_body: dict) -> httpx.Response:
    url = "https://login.live.com/oauth20_token.srf"
    headers = {"MS-CV": self.cv.increment()}

    # NOTE: No signature necessary
    return await self.session.post(url, headers=headers, data=json_body)

exchange_code_for_token(authorization_code, code_verifier) async

Source code in src/pythonxbox/authentication/xal.py
async def exchange_code_for_token(
    self, authorization_code: str, code_verifier: str
) -> OAuth2TokenResponse:
    post_body = {
        "client_id": self.app_params.app_id,
        "code": authorization_code,
        "code_verifier": code_verifier,
        "grant_type": "authorization_code",
        "redirect_uri": self.app_params.redirect_uri,
        "scope": "service::user.auth.xboxlive.com::MBI_SSL",
    }
    resp = await self.__oauth20_token_endpoint(post_body)
    resp.raise_for_status()
    return OAuth2TokenResponse.model_validate_json(resp.text)

refresh_token(refresh_token_jwt) async

Source code in src/pythonxbox/authentication/xal.py
async def refresh_token(self, refresh_token_jwt: str) -> httpx.Response:
    post_body = {
        "client_id": self.app_params.app_id,
        "refresh_token": refresh_token_jwt,
        "grant_type": "refresh_token",
        "redirect_uri": self.app_params.redirect_uri,
        "scope": "service::user.auth.xboxlive.com::MBI_SSL",
    }

    resp = await self.__oauth20_token_endpoint(post_body)
    resp.raise_for_status()
    return resp

request_sisu_authentication(device_token_jwt, code_challenge, state) async

Request Sisu authentication URL

Response holds authentication URL that needs to be called by the user in webbrowser

Returns:

Type Description
tuple[SisuAuthenticationResponse, str]

Tuple of (authentication response, sisu session id)

Source code in src/pythonxbox/authentication/xal.py
async def request_sisu_authentication(
    self, device_token_jwt: str, code_challenge: str, state: str
) -> tuple[SisuAuthenticationResponse, str]:
    """
    Request Sisu authentication URL

    Response holds authentication URL that needs to be called by the user
    in webbrowser

    Returns:
        Tuple of (authentication response, sisu session id)
    """
    url = "https://sisu.xboxlive.com/authenticate"
    headers = {"x-xbl-contract-version": "1", "MS-CV": self.cv.increment()}
    post_body = {
        "AppId": self.app_params.app_id,
        "TitleId": self.app_params.title_id,
        "RedirectUri": self.app_params.redirect_uri,
        "DeviceToken": device_token_jwt,
        "Sandbox": "RETAIL",
        "TokenType": "code",
        "Offers": ["service::user.auth.xboxlive.com::MBI_SSL"],
        "Query": {
            "display": self.client_params.query_display,
            "code_challenge": code_challenge,
            "code_challenge_method": "S256",
            "state": state,
        },
    }

    resp = await self.session.send_signed(
        "POST", url, headers=headers, json=post_body
    )
    resp.raise_for_status()
    return (
        SisuAuthenticationResponse.model_validate_json(resp.content),
        resp.headers["X-SessionId"],
    )

do_sisu_authorization(sisu_session_id, access_token_jwt, device_token_jwt) async

Sisu authorization

Returns:

Type Description
SisuAuthorizationResponse

Response with device-/title-/user-tokens

Source code in src/pythonxbox/authentication/xal.py
async def do_sisu_authorization(
    self, sisu_session_id: str, access_token_jwt: str, device_token_jwt: str
) -> SisuAuthorizationResponse:
    """
    Sisu authorization

    Returns:
        Response with device-/title-/user-tokens
    """
    url = "https://sisu.xboxlive.com/authorize"
    headers = {"MS-CV": self.cv.increment()}
    post_body = {
        "AccessToken": f"t={access_token_jwt}",
        "AppId": self.app_params.app_id,
        "DeviceToken": device_token_jwt,
        "Sandbox": "RETAIL",
        "SiteName": "user.auth.xboxlive.com",
        "SessionId": sisu_session_id,
        "ProofKey": self.session.request_signer.proof_field,
    }

    resp = await self.session.send_signed(
        "POST", url, headers=headers, json=post_body
    )
    resp.raise_for_status()
    return SisuAuthorizationResponse.model_validate_json(resp.text)

xsts_authorization(device_token_jwt, title_token_jwt, user_token_jwt, relying_party) async

Request additional XSTS tokens for specific relying parties

Source code in src/pythonxbox/authentication/xal.py
async def xsts_authorization(
    self,
    device_token_jwt: str,
    title_token_jwt: str,
    user_token_jwt: str,
    relying_party: str,
) -> XSTSResponse:
    """
    Request additional XSTS tokens for specific relying parties
    """
    url = "https://xsts.auth.xboxlive.com/xsts/authorize"
    headers = {"x-xbl-contract-version": "1", "MS-CV": self.cv.increment()}
    post_body = {
        "RelyingParty": relying_party,
        "TokenType": "JWT",
        "Properties": {
            "SandboxId": "RETAIL",
            "DeviceToken": device_token_jwt,
            "TitleToken": title_token_jwt,
            "UserTokens": [user_token_jwt],
        },
    }

    resp = await self.session.send_signed(
        "POST", url, headers=headers, json=post_body
    )
    resp.raise_for_status()
    return XSTSResponse.model_validate_json(resp.text)

auth_flow(user_input_cb) async

Does the whole XAL/Sisu authentication flow

Parameters:

Name Type Description Default
user_input_cb Callable[[str], str]

User callback which takes args: (auth_url: str) and returns the redirect URL (str)

required

Returns:

Type Description
SisuAuthorizationResponse

Sisu authorization response with all tokens

Source code in src/pythonxbox/authentication/xal.py
async def auth_flow(
    self, user_input_cb: Callable[[str], str]
) -> SisuAuthorizationResponse:
    """
    Does the whole XAL/Sisu authentication flow

    Args:
        user_input_cb: User callback which takes args: (auth_url: str) and
            returns the redirect URL (str)

    Returns:
        Sisu authorization response with all tokens
    """

    # Fetch device token
    device_token_resp = await self.request_device_token()

    # Generate states for OAUTH
    code_verifier = self._generate_code_verifier()
    code_challenge = self._get_code_challenge_from_code_verifier(code_verifier)
    state = self._generate_random_state()

    # Request Sisu authentication URL
    (
        sisu_authenticate_resp,
        sisu_session_id,
    ) = await self.request_sisu_authentication(
        device_token_resp.token, code_challenge, state
    )

    # Prompt user for redirect URI after auth
    redirect_uri = user_input_cb(sisu_authenticate_resp.msa_oauth_redirect)

    # Ensure redirect URI looks like expected
    if not redirect_uri.startswith(self.app_params.redirect_uri):
        raise Exception("Wrong data passed as redirect URI")

    # Parse URL query
    query_params = dict(parse.parse_qsl(parse.urlsplit(redirect_uri).query))

    # Extract code and state
    resp_authorization_code = query_params["code"]
    resp_state = query_params["state"]

    if resp_state != state:
        raise Exception("Response with non-matching state received")

    # Exchange authentication code for tokens
    tokens = await self.exchange_code_for_token(
        resp_authorization_code, code_verifier
    )

    # Do Sisu authorization
    return await self.do_sisu_authorization(
        sisu_session_id, tokens.access_token, device_token_resp.token
    )