Skip to content

Reference

Cookidoo API package.

Cookidoo

Unofficial Cookidoo API interface.

Init function for Cookidoo API.

Parameters:

Name Type Description Default
session ClientSession

The client session for aiohttp requests. Must use a CookieJar(unsafe=True) to support cross-domain cookies during the OAuth2 login flow.

required
cfg CookidooConfig

Cookidoo config

CookidooConfig()
on_auth_data_update Callable[[CookidooAuthData], None] | None

Optional callback invoked with the new :class:CookidooAuthData whenever the tokens change, i.e. after a login and after every (transparent) refresh. Use it to keep a persisted copy in sync without having to poll :attr:auth_data around every call. See :attr:on_auth_data_update.

None
Source code in cookidoo_api/cookidoo.py
def __init__(
    self,
    session: ClientSession,
    cfg: CookidooConfig = CookidooConfig(),
    on_auth_data_update: Callable[[CookidooAuthData], None] | None = None,
) -> None:
    """Init function for Cookidoo API.

    Parameters
    ----------
    session
        The client session for aiohttp requests.
        Must use a ``CookieJar(unsafe=True)`` to support cross-domain
        cookies during the OAuth2 login flow.
    cfg
        Cookidoo config
    on_auth_data_update
        Optional callback invoked with the new :class:`CookidooAuthData`
        whenever the tokens change, i.e. after a login and after every
        (transparent) refresh. Use it to keep a persisted copy in sync
        without having to poll :attr:`auth_data` around every call. See
        :attr:`on_auth_data_update`.

    """
    self._session = session
    self._cfg = cfg
    self._on_auth_data_update = on_auth_data_update
    self._api_headers = DEFAULT_API_HEADERS.copy()
    self._logged_in = False
    self._endpoint_overrides = {}
    self._endpoints_resolved = False
    self._endpoints_lock = asyncio.Lock()
    self._token_lock = asyncio.Lock()
    self._refresh_token = None
    self._expires_at = 0.0
    self._oidc = None
    self._rmi_links = None

localization property

Localization.

api_endpoint property

Get the api endpoint.

Returns the cookidoo domain derived from the localization URL, e.g. https://cookidoo.ch or https://cookidoo.co.uk.

auth_data property

The current OAuth2 tokens, for persistence. None until logged in.

on_auth_data_update property writable

The callback notified whenever the tokens change.

Called with the new :class:CookidooAuthData after a login and after every refresh, including the transparent one a request performs when the access token has expired. The server rotates the refresh token along with the access token, so a consumer that persists the tokens should store what the callback hands it, rather than only the result of an explicit :meth:login.

Not called by :meth:apply_auth_data or :meth:load_token, which restore tokens the consumer already holds.

Exceptions raised by the callback are caught and logged: a consumer failing to store the tokens must not break the request that triggered the refresh.

apply_auth_data

Restore a previous login from persisted tokens (no network call).

The access token is refreshed automatically on the next request if it has expired.

Source code in cookidoo_api/cookidoo.py
def apply_auth_data(self, auth_data: CookidooAuthData) -> None:
    """Restore a previous login from persisted tokens (no network call).

    The access token is refreshed automatically on the next request if it
    has expired.
    """
    self._api_headers["Authorization"] = f"Bearer {auth_data.access_token}"
    self._refresh_token = auth_data.refresh_token
    self._expires_at = auth_data.expires_at
    self._logged_in = True

login async

Perform an OAuth2 authorization-code + PKCE login.

Signs in with the configured email/password against the CIAM identity provider, exchanges the resulting code for an access/refresh token, and authenticates all subsequent API calls via a Bearer header:

  1. discover the OIDC endpoints
  2. open the authorize endpoint to reach the CIAM login form
  3. POST the credentials to the CIAM login service
  4. capture the code from the redirect to the app scheme
  5. exchange the code for tokens (public client, PKCE, no secret)

The login redirects still rely on the session cookie jar, so a CookieJar(unsafe=True) session is required. The login requests carry a browser-like User-Agent (request-scoped only) since the flow is served behind Cloudflare.

Raises:

Type Description
CookidooConfigException

If the OAuth2 client id or redirect uri was overridden with an empty value.

CookidooRequestException

If the request fails.

CookidooParseException

If the login page cannot be parsed.

CookidooAuthException

If the login fails due to invalid credentials.

Source code in cookidoo_api/cookidoo.py
async def login(self) -> None:
    """Perform an OAuth2 authorization-code + PKCE login.

    Signs in with the configured email/password against the CIAM identity
    provider, exchanges the resulting code for an access/refresh token, and
    authenticates all subsequent API calls via a ``Bearer`` header:

    1. discover the OIDC endpoints
    2. open the authorize endpoint to reach the CIAM login form
    3. POST the credentials to the CIAM login service
    4. capture the ``code`` from the redirect to the app scheme
    5. exchange the code for tokens (public client, PKCE, no secret)

    The login redirects still rely on the session cookie jar, so a
    ``CookieJar(unsafe=True)`` session is required. The login requests carry
    a browser-like ``User-Agent`` (request-scoped only) since the flow is
    served behind Cloudflare.

    Raises
    ------
    CookidooConfigException
        If the OAuth2 client id or redirect uri was overridden with an
        empty value.
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the login page cannot be parsed.
    CookidooAuthException
        If the login fails due to invalid credentials.

    """
    self._assert_oauth_client()
    try:
        oidc = await self._discovery()
        verifier, challenge = self._pkce_pair()
        state = secrets.token_urlsafe(12)
        language = self._cfg.localization.language
        params = {
            "response_type": "code",
            "client_id": self._cfg.client_id,
            "redirect_uri": self._cfg.redirect_uri,
            "market": self._cfg.localization.country_code,
            "scope": OAUTH_SCOPE,
            "state": state,
            "code_challenge": challenge,
            "code_challenge_method": "S256",
            "ui_locales": language,
        }

        # Step 2: reach the CIAM login form (follows redirects, sets cookies)
        async with self._session.get(
            URL(oidc["authorization_endpoint"]),
            params=params,
            allow_redirects=True,
            headers=LOGIN_HEADERS,
        ) as resp:
            self._check_login_page_status(resp.status)
            login_html = await resp.text()

        # Step 3: submit credentials, Step 4: capture the authorization code
        request_id = self._extract_request_id(login_html)
        code = await self._submit_credentials(request_id, state)

        # Step 5: exchange the code for tokens, which marks us logged in
        await self._exchange_code(oidc["token_endpoint"], code, verifier)

    except (CookidooAuthException, CookidooParseException):
        raise
    except TimeoutError as e:
        _LOGGER.debug("Exception: Login failed:\n %s", traceback.format_exc())
        raise CookidooRequestException(
            "Authentication failed due to connection timeout."
        ) from e
    except ClientError as e:
        _LOGGER.debug("Exception: Login failed:\n %s", traceback.format_exc())
        raise CookidooRequestException(
            "Authentication failed due to request exception."
        ) from e

refresh async

Refresh the access token using the stored refresh token.

Raises:

Type Description
CookidooAuthException

If there is no refresh token or the refresh is rejected.

CookidooConfigException

If the OAuth2 client id or redirect uri was overridden with an empty value.

CookidooRequestException

If the discovery or token request fails or times out.

Source code in cookidoo_api/cookidoo.py
async def refresh(self) -> None:
    """Refresh the access token using the stored refresh token.

    Raises
    ------
    CookidooAuthException
        If there is no refresh token or the refresh is rejected.
    CookidooConfigException
        If the OAuth2 client id or redirect uri was overridden with an
        empty value.
    CookidooRequestException
        If the discovery or token request fails or times out.

    """
    if self._refresh_token is None:
        raise CookidooAuthException("Cannot refresh: no refresh token available.")
    self._assert_oauth_client()
    try:
        # Inside the try: the discovery request can fail the same way the
        # token request can, and callers only expect CookidooException.
        oidc = await self._discovery()
        async with self._session.post(
            URL(oidc["token_endpoint"]),
            data={
                "grant_type": "refresh_token",
                "refresh_token": self._refresh_token,
                "client_id": self._cfg.client_id,
            },
            headers=LOGIN_HEADERS,
        ) as resp:
            if resp.status != HTTPStatus.OK:
                raise CookidooAuthException(
                    f"Token refresh failed (status {resp.status})."
                )
            payload = cast(dict[str, object], await resp.json())
    except TimeoutError as e:
        _LOGGER.debug(
            "Exception: Token refresh failed:\n %s", traceback.format_exc()
        )
        raise CookidooRequestException(
            "Token refresh failed due to connection timeout."
        ) from e
    except ClientError as e:
        _LOGGER.debug(
            "Exception: Token refresh failed:\n %s", traceback.format_exc()
        )
        raise CookidooRequestException(
            "Token refresh failed due to request exception."
        ) from e
    self._apply_tokens(payload)

save_token

Save the OAuth2 tokens to a file for later reuse.

Parameters:

Name Type Description Default
path str | Path

Path to the file where the tokens will be saved.

required
Source code in cookidoo_api/cookidoo.py
def save_token(self, path: str | Path) -> None:
    """Save the OAuth2 tokens to a file for later reuse.

    Parameters
    ----------
    path
        Path to the file where the tokens will be saved.

    """
    if (auth_data := self.auth_data) is None:
        raise CookidooConfigException("Cannot save token: not logged in.")
    Path(path).write_text(json.dumps(vars(auth_data)), encoding="utf-8")

load_token

Restore the OAuth2 tokens from a file saved with :meth:save_token.

Parameters:

Name Type Description Default
path str | Path

Path to the file containing the saved tokens.

required

Raises:

Type Description
CookidooConfigException

If the token file cannot be read or parsed.

Source code in cookidoo_api/cookidoo.py
def load_token(self, path: str | Path) -> None:
    """Restore the OAuth2 tokens from a file saved with :meth:`save_token`.

    Parameters
    ----------
    path
        Path to the file containing the saved tokens.

    Raises
    ------
    CookidooConfigException
        If the token file cannot be read or parsed.

    """
    try:
        data = json.loads(Path(path).read_text(encoding="utf-8"))
        self.apply_auth_data(CookidooAuthData(**data))
    except (OSError, json.JSONDecodeError, TypeError) as e:
        raise CookidooConfigException(f"Cannot load token from {path}.") from e

get_user_info async

Get user info.

Returns:

Type Description
CookidooUserInfo

The user info

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def get_user_info(
    self,
) -> CookidooUserInfo:
    """Get user info.

    Returns
    -------
    CookidooUserInfo
        The user info

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """

    await self._ensure_endpoints()
    url = self.api_endpoint / self._path(
        "community-profile:user-private-profile"
    ).format(**self._cfg.localization.__dict__)
    result = self._ensure_mapping(
        await self._request_json("get", url, "loading user info"),
        "loading user info",
    )
    return self._parse_result(
        "loading user info",
        lambda: cookidoo_user_info_from_json(cast(CommunityProfileJSON, result)),
    )

get_active_subscription async

Get active subscription if any.

Returns:

Type Description
CookidooSubscription

The active subscription

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def get_active_subscription(
    self,
) -> CookidooSubscription | None:
    """Get active subscription if any.

    Returns
    -------
    CookidooSubscription
        The active subscription

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """

    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("ownership:subscriptions").format(
        **self._cfg.localization.__dict__
    )
    subscriptions = self._ensure_sequence(
        await self._request_json("get", url, "loading active subscription"),
        "loading active subscription",
    )
    try:
        if subscription := next(
            (
                subscription
                for subscription in subscriptions
                if isinstance(subscription, Mapping) and subscription["active"]
            ),
            None,
        ):
            return self._parse_result(
                "loading active subscription",
                lambda: cookidoo_subscription_from_json(
                    cast(SubscriptionJSON, subscription)
                ),
            )
    except KeyError as e:
        raise CookidooParseException(
            "Loading active subscription failed during parsing of request response."
        ) from e
    return None

get_devices async

Get the Thermomix appliances paired to the account.

Returns:

Type Description
list[CookidooDevice]

The paired appliances, identified by machine type (e.g. TM7). An empty list when no appliance is paired.

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def get_devices(self) -> list[CookidooDevice]:
    """Get the Thermomix appliances paired to the account.

    Returns
    -------
    list[CookidooDevice]
        The paired appliances, identified by machine type (e.g. ``TM7``).
        An empty list when no appliance is paired.

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path(
        "customer-devices:thermomix-versions"
    ).format(**self._cfg.localization.__dict__)
    result = await self._request_json("get", url, "loading devices")
    if result is None:
        # An account without a paired appliance gets a 204 No Content.
        return []
    models = self._ensure_sequence(result, "loading devices")
    return self._parse_result(
        "loading devices",
        lambda: [cookidoo_device_from_json(cast(str, model)) for model in models],
    )

get_monitored_device_ids async

Get the appliance IDs currently available for remote monitoring.

Note this is distinct from :meth:get_devices (all paired appliances): an appliance only appears here while it is online/reachable for monitoring, and the identifier is the opaque remote-monitoring device id.

Returns:

Type Description
list[str]

The remote-monitoring device ids (empty when none are available).

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def get_monitored_device_ids(self) -> list[str]:
    """Get the appliance IDs currently available for remote monitoring.

    Note this is distinct from :meth:`get_devices` (all paired appliances):
    an appliance only appears here while it is online/reachable for
    monitoring, and the identifier is the opaque remote-monitoring device id.

    Returns
    -------
    list[str]
        The remote-monitoring device ids (empty when none are available).

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    links = await self._resolve_rmi_links()
    url = links.get(RMI_DEVICES)
    if url is None:
        raise CookidooParseException("rmi:devices link missing.")
    devices = self._ensure_sequence(
        await self._request_json(
            "get", URL(url.split("{")[0]), "loading monitored devices"
        ),
        "loading monitored devices",
    )
    return self._parse_result(
        "loading monitored devices",
        lambda: [
            cast(str, cast(Mapping[str, object], device)["deviceId"])
            for device in devices
        ],
    )

register_push_token async

Register a push token to receive remote-monitoring cook-state updates.

Appliance state is delivered as a Firebase Cloud Messaging data message to the registered token; obtaining the token and receiving the messages is the caller's responsibility. Decode received payloads with :func:cookidoo_api.cooking_activity_from_push.

Parameters:

Name Type Description Default
push_token str

The FCM registration token to deliver updates to.

required
mobile_app_id str

A stable per-installation identifier for this client.

required

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def register_push_token(self, push_token: str, mobile_app_id: str) -> None:
    """Register a push token to receive remote-monitoring cook-state updates.

    Appliance state is delivered as a Firebase Cloud Messaging data message
    to the registered token; obtaining the token and receiving the messages
    is the caller's responsibility. Decode received payloads with
    :func:`cookidoo_api.cooking_activity_from_push`.

    Parameters
    ----------
    push_token
        The FCM registration token to deliver updates to.
    mobile_app_id
        A stable per-installation identifier for this client.

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    links = await self._resolve_rmi_links()
    url = links.get(RMI_REGISTER_TOKEN)
    if url is None:
        raise CookidooParseException("rmi:register-token link missing.")
    await self._request_json(
        "post",
        URL(url),
        "registering push token",
        json={
            "token": push_token,
            "bundleId": PUSH_BUNDLE_ID,
            "platform": PUSH_PLATFORM,
            "mobileAppId": mobile_app_id,
        },
        headers={"rmi-api-version": RMI_API_VERSION},
        parse_response=False,
    )

unregister_push_token async

Unregister a previously registered push token.

Parameters:

Name Type Description Default
push_token str

The FCM registration token to stop delivering updates to.

required

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def unregister_push_token(self, push_token: str) -> None:
    """Unregister a previously registered push token.

    Parameters
    ----------
    push_token
        The FCM registration token to stop delivering updates to.

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    links = await self._resolve_rmi_links()
    url = links.get(RMI_UNREGISTER)
    if url is None:
        raise CookidooParseException("rmi:unregister link missing.")
    await self._request_json(
        "delete",
        URL(url),
        "unregistering push token",
        json={"tokens": [push_token]},
        headers={"rmi-api-version": RMI_API_VERSION},
        parse_response=False,
    )

get_recipe_details async

Get recipe details.

Parameters:

Name Type Description Default
id str

The id of the recipe

required

Returns:

Type Description
CookidooShoppingRecipeDetails

The recipe details

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def get_recipe_details(self, id: str) -> CookidooShoppingRecipeDetails:
    """Get recipe details.

    Parameters
    ----------
    id
        The id of the recipe

    Returns
    -------
    CookidooShoppingRecipeDetails
        The recipe details

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """

    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("recipe:details").format(
        **self._cfg.localization.__dict__, id=id
    )
    result = self._ensure_mapping(
        await self._request_json("get", url, "loading recipe details"),
        "loading recipe details",
    )
    return self._parse_result(
        "loading recipe details",
        lambda: cookidoo_recipe_details_from_json(
            cast(RecipeDetailsJSON, result),
            self._cfg.localization,
        ),
    )

search_recipes async

Search recipes in Cookidoo (GET).

Uses the same API base as the rest of the client (api_endpoint): {api_endpoint}/search/{locale}

Parameters:

Name Type Description Default
query str | None

Optional search query (e.g. "chicken", "pasta").

None
locale str | None

Locale for the search path (e.g. "es", "en", "de"). Defaults to the first part of the configured language (e.g. "de-CH" -> "de").

None
accessories str | list[str] | None

Optional comma-separated accessory filters (e.g. "includingFriend,includingBladeCover,includingBladeCoverWithPeeler,includingCutter,includingSensor").

None
languages str | list[str] | None

Optional comma-separated language codes (e.g. "en,es").

None
categories str | list[str] | None

Optional comma-separated category IDs.

None
countries str | list[str] | None

Optional comma-separated country codes (e.g. "ar").

None
ingredients str | list[str] | None

Optional comma-separated ingredients.

None
exclude_ingredients str | list[str] | None

Optional comma-separated excluded ingredients.

None
tags str | list[str] | None

Optional comma-separated tags.

None
ratings str | list[str] | None

Optional comma-separated ratings (e.g. "5,4").

None
difficulty str | None

Optional difficulty (e.g. "easy", "medium", "hard").

None
preparation_time int | None

Optional preparation time in seconds.

None
total_time int | None

Optional total time in seconds.

None
portions int | None

Optional portions count.

None
page int | None

Optional page number (API-dependent, often 0- or 1-based).

None
page_size int | None

Optional page size (API-dependent; common keys: pageSize).

None
tmv ThermomixMachineType | str | list[ThermomixMachineType | str] | None

Optional Thermomix machine version. Use ThermomixMachineType (e.g. ThermomixMachineType.TM7) or a string ("TM7", "TM6", "TM5").

None

Returns:

Type Description
CookidooSearchResult

Search result with recipes and total count.

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore.

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def search_recipes(
    self,
    query: str | None = None,
    *,
    locale: str | None = None,
    accessories: str | list[str] | None = None,
    languages: str | list[str] | None = None,
    categories: str | list[str] | None = None,
    countries: str | list[str] | None = None,
    ingredients: str | list[str] | None = None,
    exclude_ingredients: str | list[str] | None = None,
    tags: str | list[str] | None = None,
    ratings: str | list[str] | None = None,
    difficulty: str | None = None,
    preparation_time: int | None = None,
    total_time: int | None = None,
    portions: int | None = None,
    page: int | None = None,
    page_size: int | None = None,
    tmv: ThermomixMachineType
    | str
    | list[ThermomixMachineType | str]
    | None = None,
) -> CookidooSearchResult:
    """Search recipes in Cookidoo (GET).

    Uses the same API base as the rest of the client (api_endpoint):
    {api_endpoint}/search/{locale}

    Parameters
    ----------
    query
        Optional search query (e.g. "chicken", "pasta").
    locale
        Locale for the search path (e.g. "es", "en", "de").
        Defaults to the first part of the configured language (e.g. "de-CH" -> "de").
    accessories
        Optional comma-separated accessory filters
        (e.g. "includingFriend,includingBladeCover,includingBladeCoverWithPeeler,includingCutter,includingSensor").
    languages
        Optional comma-separated language codes (e.g. "en,es").
    categories
        Optional comma-separated category IDs.
    countries
        Optional comma-separated country codes (e.g. "ar").
    ingredients
        Optional comma-separated ingredients.
    exclude_ingredients
        Optional comma-separated excluded ingredients.
    tags
        Optional comma-separated tags.
    ratings
        Optional comma-separated ratings (e.g. "5,4").
    difficulty
        Optional difficulty (e.g. "easy", "medium", "hard").
    preparation_time
        Optional preparation time in seconds.
    total_time
        Optional total time in seconds.
    portions
        Optional portions count.
    page
        Optional page number (API-dependent, often 0- or 1-based).
    page_size
        Optional page size (API-dependent; common keys: pageSize).
    tmv
        Optional Thermomix machine version. Use ``ThermomixMachineType``
        (e.g. ``ThermomixMachineType.TM7``) or a string ("TM7", "TM6", "TM5").

    Returns
    -------
    CookidooSearchResult
        Search result with recipes and total count.

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore.
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    if locale is None:
        locale = self._cfg.localization.language.split("-")[0]
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("search:home").format(locale=locale)
    params: dict[str, str] = {}
    if query is not None:
        params["query"] = query
    if accessories is not None and (
        normalized := normalize_list_param(accessories)
    ):
        params["accessories"] = normalized
    if languages is not None and (normalized := normalize_list_param(languages)):
        params["languages"] = normalized
    if categories is not None and (normalized := normalize_list_param(categories)):
        params["categories"] = normalized
    if countries is not None and (normalized := normalize_list_param(countries)):
        params["countries"] = normalized
    if ingredients is not None and (
        normalized := normalize_list_param(ingredients)
    ):
        params["ingredients"] = normalized
    if exclude_ingredients is not None and (
        normalized := normalize_list_param(exclude_ingredients)
    ):
        params["excludeIngredients"] = normalized
    if tags is not None and (normalized := normalize_list_param(tags)):
        params["tags"] = normalized
    if ratings is not None and (normalized := normalize_list_param(ratings)):
        params["ratings"] = normalized
    if difficulty is not None:
        params["difficulty"] = difficulty
    if preparation_time is not None:
        params["preparationTime"] = str(preparation_time)
    if total_time is not None:
        params["totalTime"] = str(total_time)
    if portions is not None:
        params["portions"] = str(portions)
    if page is not None:
        params["page"] = str(page)
    if page_size is not None:
        params["pageSize"] = str(page_size)
    if tmv is not None and (normalized := normalize_tmv_param(tmv)):
        params["tmv"] = normalized
    result = await self._request_json("get", url, "search recipes", params=params)
    if result is None:
        return CookidooSearchResult(recipes=[], total=0)
    if not isinstance(result, dict):
        raise CookidooParseException(
            "Search recipes failed during parsing of request response."
        )
    return cookidoo_search_result_from_json(
        cast(SearchResultJSON, result), self._cfg.localization
    )

get_custom_recipe async

Get custom recipe.

Parameters:

Name Type Description Default
id str

The id of the custom recipe

required

Returns:

Type Description
CookidooCustomRecipe

The custom recipe

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def get_custom_recipe(self, id: str) -> CookidooCustomRecipe:
    """Get custom recipe.

    Parameters
    ----------
    id
        The id of the custom recipe

    Returns
    -------
    CookidooCustomRecipe
        The custom recipe

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """

    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("customer-recipes:recipe-details").format(
        **self._cfg.localization.__dict__, id=id
    )
    result = self._ensure_mapping(
        await self._request_json("get", url, "loading custom recipe"),
        "loading custom recipe",
    )
    return self._parse_result(
        "loading custom recipe",
        lambda: cookidoo_custom_recipe_from_json(
            cast(CustomRecipeJSON, result),
            self._cfg.localization,
        ),
    )

list_custom_recipes async

List custom recipes.

Source code in cookidoo_api/cookidoo.py
async def list_custom_recipes(self) -> list[CookidooCustomRecipe]:
    """List custom recipes."""
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("customer-recipes:recipe-create").format(
        **self._cfg.localization.__dict__
    )
    result = self._ensure_mapping(
        await self._request_json(
            "get",
            url,
            "listing custom recipes",
            headers={"ACCEPT": CUSTOM_RECIPES_PATH_ACCEPT},
        ),
        "listing custom recipes",
    )
    if not isinstance(result.get("items"), list):
        raise CookidooParseException(
            "Listing custom recipes failed during parsing of request response."
        )

    custom_recipes = cast(CustomRecipesJSON, result)
    return self._parse_result(
        "listing custom recipes",
        lambda: [
            cookidoo_custom_recipe_from_json(recipe, self._cfg.localization)
            for recipe in custom_recipes["items"]
        ],
    )

add_custom_recipe_from async

Add custom recipe.

Parameters:

Name Type Description Default
recipeId str

The base recipe to copy

required
servingSize int

The serving size of the custom recipe

required

Returns:

Type Description
CookidooCustomRecipe

The added custom recipe

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def add_custom_recipe_from(
    self, recipeId: str, servingSize: int
) -> CookidooCustomRecipe:
    """Add custom recipe.

    Parameters
    ----------
    recipeId
        The base recipe to copy
    servingSize
        The serving size of the custom recipe

    Returns
    -------
    CookidooCustomRecipe
        The added custom recipe

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    await self._ensure_endpoints()
    json_data = {
        "recipeUrl": str(
            self.api_endpoint
            / self._path("recipe:details").format(
                **self._cfg.localization.__dict__, id=recipeId
            )
        ),
        "servingSize": servingSize,
    }
    url = self.api_endpoint / self._path("customer-recipes:recipe-create").format(
        **self._cfg.localization.__dict__
    )
    result = self._ensure_mapping(
        await self._request_json("post", url, "add custom recipe", json=json_data),
        "add custom recipe",
    )
    return self._parse_result(
        "add custom recipe",
        lambda: cookidoo_custom_recipe_from_json(
            cast(CustomRecipeJSON, result),
            self._cfg.localization,
        ),
    )

remove_custom_recipe async

Remove custom recipe.

Parameters:

Name Type Description Default
custom_recipe_id str

The custom recipe id to remove

required

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def remove_custom_recipe(
    self,
    custom_recipe_id: str,
) -> None:
    """Remove custom recipe.

    Parameters
    ----------
    custom_recipe_id
        The custom recipe id to remove

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("customer-recipes:recipe-details").format(
        **self._cfg.localization.__dict__, id=custom_recipe_id
    )
    await self._request_json(
        "delete", url, "remove custom recipe", parse_response=False
    )

get_shopping_list_recipes async

Get recipes.

Returns:

Type Description
list[CookidooShoppingRecipe]

The list of the recipes

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def get_shopping_list_recipes(
    self,
) -> list[CookidooShoppingRecipe]:
    """Get recipes.

    Returns
    -------
    list[CookidooShoppingRecipe]
        The list of the recipes

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """

    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("pantry:home").format(
        **self._cfg.localization.__dict__
    )
    result = self._ensure_mapping(
        await self._request_json("get", url, "loading recipes"),
        "loading recipes",
    )
    return self._parse_result(
        "loading recipes",
        lambda: [
            cookidoo_recipe_from_json(
                cast(RecipeJSON, recipe), self._cfg.localization
            )
            for recipe in [
                *cast(Sequence[object], result["recipes"]),
                *cast(Sequence[object], result["customerRecipes"]),
            ]
        ],
    )

get_ingredient_items async

Get ingredient items.

Returns:

Type Description
list[CookidooIngredientItem]

The list of the ingredient items

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def get_ingredient_items(
    self,
) -> list[CookidooIngredientItem]:
    """Get ingredient items.

    Returns
    -------
    list[CookidooIngredientItem]
        The list of the ingredient items

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """

    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("pantry:home").format(
        **self._cfg.localization.__dict__
    )
    result = self._ensure_mapping(
        await self._request_json("get", url, "loading ingredient items"),
        "loading ingredient items",
    )
    return self._parse_result(
        "loading ingredient items",
        lambda: [
            cookidoo_ingredient_item_from_json(cast(ItemJSON, ingredient))
            for recipe in [
                *cast(Sequence[Mapping[str, object]], result["recipes"]),
                *cast(Sequence[Mapping[str, object]], result["customerRecipes"]),
            ]
            for ingredient in cast(
                Sequence[object], recipe["recipeIngredientGroups"]
            )
        ],
    )

add_ingredient_items_for_recipes async

Add ingredient items for recipes.

Parameters:

Name Type Description Default
recipe_ids list[str]

The recipe ids for the ingredient items to add to the shopping list

required

Returns:

Type Description
list[CookidooIngredientItem]

The list of the added ingredient items

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def add_ingredient_items_for_recipes(
    self,
    recipe_ids: list[str],
) -> list[CookidooIngredientItem]:
    """Add ingredient items for recipes.

    Parameters
    ----------
    recipe_ids
        The recipe ids for the ingredient items to add to the shopping list

    Returns
    -------
    list[CookidooIngredientItem]
        The list of the added ingredient items

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    json_data = {"recipeIDs": recipe_ids}
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("pantry:recipe-ingredients").format(
        **self._cfg.localization.__dict__
    )
    result = self._ensure_mapping(
        await self._request_json(
            "post", url, "add ingredient items for recipes", json=json_data
        ),
        "add ingredient items for recipes",
    )
    return self._parse_result(
        "loading added ingredient items",
        lambda: [
            cookidoo_ingredient_item_from_json(cast(ItemJSON, ingredient))
            for recipe in cast(Sequence[Mapping[str, object]], result["data"])
            for ingredient in cast(
                Sequence[object], recipe["recipeIngredientGroups"]
            )
        ],
    )

remove_ingredient_items_for_recipes async

Remove ingredient items for recipes.

Parameters:

Name Type Description Default
recipe_ids list[str]

The recipe ids for the ingredient items to remove to the shopping list

required

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def remove_ingredient_items_for_recipes(
    self,
    recipe_ids: list[str],
) -> None:
    """Remove ingredient items for recipes.

    Parameters
    ----------
    recipe_ids
        The recipe ids for the ingredient items to remove to the shopping list

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    json_data = {"recipeIDs": recipe_ids}
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("pantry:remove-recipe").format(
        **self._cfg.localization.__dict__
    )
    await self._request_json(
        "post",
        url,
        "remove ingredient items for recipes",
        json=json_data,
        parse_response=False,
    )

edit_ingredient_items_ownership async

Edit ownership ingredient items.

Parameters:

Name Type Description Default
ingredient_items list[CookidooIngredientItem]

The ingredient items to change the the is_owned value for

required

Returns:

Type Description
list[CookidooIngredientItem]

The list of the edited ingredient items

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def edit_ingredient_items_ownership(
    self,
    ingredient_items: list[CookidooIngredientItem],
) -> list[CookidooIngredientItem]:
    """Edit ownership ingredient items.

    Parameters
    ----------
    ingredient_items
        The ingredient items to change the the `is_owned` value for

    Returns
    -------
    list[CookidooIngredientItem]
        The list of the edited ingredient items

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    json_data = {
        "ingredients": [
            {
                "id": ingredient_item.id,
                "isOwned": ingredient_item.is_owned,
                "ownedTimestamp": int(time.time()),
            }
            for ingredient_item in ingredient_items
        ]
    }
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path(
        "pantry:edit-ingredients-ownership"
    ).format(**self._cfg.localization.__dict__)
    result = self._ensure_mapping(
        await self._request_json(
            "post", url, "edit ingredient items ownership", json=json_data
        ),
        "edit ingredient items ownership",
    )
    return self._parse_result(
        "loading edited ingredient items",
        lambda: [
            cookidoo_ingredient_item_from_json(cast(ItemJSON, ingredient))
            for ingredient in cast(Sequence[object], result["data"])
        ],
    )

add_ingredient_items_for_custom_recipes async

Add ingredient items for custom recipes.

Parameters:

Name Type Description Default
recipe_ids list[str]

The recipe ids for the ingredient items to add to the shopping list

required

Returns:

Type Description
list[CookidooIngredientItem]

The list of the added ingredient items

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def add_ingredient_items_for_custom_recipes(
    self,
    recipe_ids: list[str],
) -> list[CookidooIngredientItem]:
    """Add ingredient items for custom recipes.

    Parameters
    ----------
    recipe_ids
        The recipe ids for the ingredient items to add to the shopping list

    Returns
    -------
    list[CookidooIngredientItem]
        The list of the added ingredient items

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    json_data = {
        "recipeIDs": [
            {"id": recipe_id, "source": "CUSTOMER"} for recipe_id in recipe_ids
        ]
    }
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("pantry:recipe-ingredients").format(
        **self._cfg.localization.__dict__
    )
    result = self._ensure_mapping(
        await self._request_json(
            "post", url, "add ingredient items for custom recipes", json=json_data
        ),
        "add ingredient items for custom recipes",
    )
    return self._parse_result(
        "loading added ingredient items",
        lambda: [
            cookidoo_ingredient_item_from_json(cast(ItemJSON, ingredient))
            for recipe in cast(Sequence[Mapping[str, object]], result["data"])
            for ingredient in cast(
                Sequence[object], recipe["recipeIngredientGroups"]
            )
        ],
    )

remove_ingredient_items_for_custom_recipes async

Remove ingredient items for custom recipes.

Parameters:

Name Type Description Default
recipe_ids list[str]

The custom recipe ids for the ingredient items to remove to the shopping list

required

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def remove_ingredient_items_for_custom_recipes(
    self,
    recipe_ids: list[str],
) -> None:
    """Remove ingredient items for custom recipes.

    Parameters
    ----------
    recipe_ids
        The custom recipe ids for the ingredient items to remove to the shopping list

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    json_data = {"recipeIDs": recipe_ids}
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("pantry:remove-recipe").format(
        **self._cfg.localization.__dict__
    )
    await self._request_json(
        "post",
        url,
        "remove ingredient items for custom recipes",
        json=json_data,
        parse_response=False,
    )

get_additional_items async

Get additional items.

Returns:

Type Description
list[CookidooAdditionalItem]

The list of the additional items

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def get_additional_items(
    self,
) -> list[CookidooAdditionalItem]:
    """Get additional items.

    Returns
    -------
    list[CookidooAdditionalItem]
        The list of the additional items

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """

    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("pantry:home").format(
        **self._cfg.localization.__dict__
    )
    result = self._ensure_mapping(
        await self._request_json("get", url, "loading additional items"),
        "loading additional items",
    )
    return self._parse_result(
        "loading additional items",
        lambda: [
            cookidoo_additional_item_from_json(
                cast(AdditionalItemJSON, additional_item)
            )
            for additional_item in cast(Sequence[object], result["additionalItems"])
        ],
    )

add_additional_items async

Create additional items.

Parameters:

Name Type Description Default
additional_item_names list[str]

The additional item names to create, only the label can be set, as the default state is_owned=false is forced (chain with immediate update call for work-around)

required

Returns:

Type Description
list[CookidooAdditionalItem]

The list of the added additional items

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def add_additional_items(
    self,
    additional_item_names: list[str],
) -> list[CookidooAdditionalItem]:
    """Create additional items.

    Parameters
    ----------
    additional_item_names
        The additional item names to create, only the label can be set, as the default state `is_owned=false` is forced (chain with immediate update call for work-around)

    Returns
    -------
    list[CookidooAdditionalItem]
        The list of the added additional items

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    json_data = {"itemsValue": additional_item_names}
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("pantry:add-additional-items-v2").format(
        **self._cfg.localization.__dict__
    )
    result = self._ensure_mapping(
        await self._request_json(
            "post", url, "add additional items", json=json_data
        ),
        "add additional items",
    )
    return self._parse_result(
        "loading added additional items",
        lambda: [
            cookidoo_additional_item_from_json(
                cast(AdditionalItemJSON, additional_item)
            )
            for additional_item in cast(Sequence[object], result["data"])
        ],
    )

edit_additional_items async

Edit additional items.

Parameters:

Name Type Description Default
additional_items list[CookidooAdditionalItem]

The additional items to change the the name value for

required

Returns:

Type Description
list[CookidooAdditionalItem]

The list of the edited additional items

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def edit_additional_items(
    self,
    additional_items: list[CookidooAdditionalItem],
) -> list[CookidooAdditionalItem]:
    """Edit additional items.

    Parameters
    ----------
    additional_items
        The additional items to change the the `name` value for

    Returns
    -------
    list[CookidooAdditionalItem]
        The list of the edited additional items

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    json_data = {
        "additionalItems": [
            {
                "id": additional_item.id,
                "name": additional_item.name,
            }
            for additional_item in additional_items
        ]
    }
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("pantry:edit-additional-items").format(
        **self._cfg.localization.__dict__
    )
    result = self._ensure_mapping(
        await self._request_json(
            "post", url, "edit additional items", json=json_data
        ),
        "edit additional items",
    )
    return self._parse_result(
        "loading edited additional items",
        lambda: [
            cookidoo_additional_item_from_json(
                cast(AdditionalItemJSON, additional_item)
            )
            for additional_item in cast(Sequence[object], result["data"])
        ],
    )

edit_additional_items_ownership async

Edit ownership additional items.

Parameters:

Name Type Description Default
additional_items list[CookidooAdditionalItem]

The additional items to change the the is_owned value for

required

Returns:

Type Description
list[CookidooAdditionalItem]

The list of the edited additional items

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def edit_additional_items_ownership(
    self,
    additional_items: list[CookidooAdditionalItem],
) -> list[CookidooAdditionalItem]:
    """Edit ownership additional items.

    Parameters
    ----------
    additional_items
        The additional items to change the the `is_owned` value for

    Returns
    -------
    list[CookidooAdditionalItem]
        The list of the edited additional items

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    json_data = {
        "additionalItems": [
            {
                "id": additional_item.id,
                "isOwned": additional_item.is_owned,
                "ownedTimestamp": int(time.time()),
            }
            for additional_item in additional_items
        ]
    }
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path(
        "pantry:edit-additional-items-ownership"
    ).format(**self._cfg.localization.__dict__)
    result = self._ensure_mapping(
        await self._request_json(
            "post", url, "edit additional items ownership", json=json_data
        ),
        "edit additional items ownership",
    )
    return self._parse_result(
        "loading edited additional items",
        lambda: [
            cookidoo_additional_item_from_json(
                cast(AdditionalItemJSON, additional_item)
            )
            for additional_item in cast(Sequence[object], result["data"])
        ],
    )

remove_additional_items async

Remove additional items.

Parameters:

Name Type Description Default
additional_item_ids list[str]

The additional item ids to remove

required

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def remove_additional_items(
    self,
    additional_item_ids: list[str],
) -> None:
    """Remove additional items.

    Parameters
    ----------
    additional_item_ids
        The additional item ids to remove

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    json_data = {"additionalItemIDs": additional_item_ids}
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("pantry:remove-additional-items").format(
        **self._cfg.localization.__dict__
    )
    await self._request_json(
        "post",
        url,
        "remove additional items",
        json=json_data,
        parse_response=False,
    )

clear_shopping_list async

Remove all additional items, ingredients and recipes.

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def clear_shopping_list(
    self,
) -> None:
    """Remove all additional items, ingredients and recipes.

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("pantry:home").format(
        **self._cfg.localization.__dict__
    )
    await self._request_json(
        "delete", url, "clear shopping list", parse_response=False
    )

count_managed_collections async

Get managed collections.

Returns:

Type Description
tuple[int, int]

The number of managed collections and the number of pages

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def count_managed_collections(self) -> tuple[int, int]:
    """Get managed collections.

    Returns
    -------
    tuple[int, int]
        The number of managed collections and the number of pages

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """

    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("organize:api-managed-list").format(
        **self._cfg.localization.__dict__
    )
    result = self._ensure_mapping(
        await self._request_json(
            "get",
            url,
            "loading managed collections",
            headers={"ACCEPT": MANAGED_COLLECTIONS_PATH_ACCEPT},
        ),
        "loading managed collections",
    )
    return self._parse_result(
        "loading managed collections",
        lambda: (
            cast(PaginationJSON, result["page"])["totalElements"],
            cast(PaginationJSON, result["page"])["totalPages"],
        ),
    )

get_managed_collections async

Get managed collections.

Parameters:

Name Type Description Default
page int

The page of the managed collections

0

Returns:

Type Description
list[CookidooCollection]

The list of the managed collections

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def get_managed_collections(self, page: int = 0) -> list[CookidooCollection]:
    """Get managed collections.

    Parameters
    ----------
    page
        The page of the managed collections

    Returns
    -------
    list[CookidooCollection]
        The list of the managed collections

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """

    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("organize:api-managed-list").format(
        **self._cfg.localization.__dict__
    )
    result = self._ensure_mapping(
        await self._request_json(
            "get",
            url,
            "loading managed collections",
            params={"page": str(page)},
            headers={"ACCEPT": MANAGED_COLLECTIONS_PATH_ACCEPT},
        ),
        "loading managed collections",
    )
    return self._parse_result(
        "loading managed collections",
        lambda: [
            cookidoo_collection_from_json(cast(ManagedCollectionJSON, item))
            for item in cast(Sequence[object], result["managedlists"])
        ],
    )

add_managed_collection async

Add managed collections.

Parameters:

Name Type Description Default
managed_collection_id str

The managed collection id to add

required

Returns:

Type Description
CookidooCollection

The added managed collection

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def add_managed_collection(
    self,
    managed_collection_id: str,
) -> CookidooCollection:
    """Add managed collections.

    Parameters
    ----------
    managed_collection_id
        The managed collection id to add

    Returns
    -------
    CookidooCollection
        The added managed collection

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    json_data = {"collectionId": managed_collection_id}
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("organize:api-managed-list").format(
        **self._cfg.localization.__dict__
    )
    result = self._ensure_mapping(
        await self._request_json(
            "post",
            url,
            "add managed collection",
            json=json_data,
            headers={"ACCEPT": MANAGED_COLLECTIONS_PATH_ACCEPT},
        ),
        "add managed collection",
    )
    return self._parse_result(
        "loading added managed collection",
        lambda: cookidoo_collection_from_json(
            cast(ManagedCollectionJSON, result["content"])
        ),
    )

remove_managed_collection async

Remove managed collection.

Parameters:

Name Type Description Default
managed_collection_id str

The managed collection id to remove

required

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def remove_managed_collection(
    self,
    managed_collection_id: str,
) -> None:
    """Remove managed collection.

    Parameters
    ----------
    managed_collection_id
        The managed collection id to remove

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("organize:api-managed-list-single").format(
        **self._cfg.localization.__dict__, id=managed_collection_id
    )
    await self._request_json(
        "delete",
        url,
        "remove managed collection",
        headers={"ACCEPT": MANAGED_COLLECTIONS_PATH_ACCEPT},
        parse_response=False,
    )

count_custom_collections async

Get custom collections.

Returns:

Type Description
tuple[int, int]

The number of custom collections and the number of pages

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def count_custom_collections(self) -> tuple[int, int]:
    """Get custom collections.

    Returns
    -------
    tuple[int, int]
        The number of custom collections and the number of pages

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """

    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("organize:api-custom-list").format(
        **self._cfg.localization.__dict__
    )
    result = self._ensure_mapping(
        await self._request_json(
            "get",
            url,
            "loading custom collections",
            headers={"ACCEPT": CUSTOM_COLLECTIONS_PATH_ACCEPT},
        ),
        "loading custom collections",
    )
    return self._parse_result(
        "loading custom collections",
        lambda: (
            cast(PaginationJSON, result["page"])["totalElements"],
            cast(PaginationJSON, result["page"])["totalPages"],
        ),
    )

get_custom_collections async

Get custom collections.

Parameters:

Name Type Description Default
page int

The page of the custom collections

0

Returns:

Type Description
list[CookidooCollection]

The list of the custom collections

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def get_custom_collections(self, page: int = 0) -> list[CookidooCollection]:
    """Get custom collections.

    Parameters
    ----------
    page
        The page of the custom collections

    Returns
    -------
    list[CookidooCollection]
        The list of the custom collections

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """

    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("organize:api-custom-list").format(
        **self._cfg.localization.__dict__
    )
    result = self._ensure_mapping(
        await self._request_json(
            "get",
            url,
            "loading custom collections",
            params={"page": str(page)},
            headers={"ACCEPT": CUSTOM_COLLECTIONS_PATH_ACCEPT},
        ),
        "loading custom collections",
    )
    return self._parse_result(
        "loading custom collections",
        lambda: [
            cookidoo_collection_from_json(cast(CustomCollectionJSON, item))
            for item in cast(Sequence[object], result["customlists"])
        ],
    )

add_custom_collection async

Add custom collections.

Parameters:

Name Type Description Default
custom_collection_name str

The custom collection name to add

required

Returns:

Type Description
CookidooCollection

The added custom collection

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def add_custom_collection(
    self,
    custom_collection_name: str,
) -> CookidooCollection:
    """Add custom collections.

    Parameters
    ----------
    custom_collection_name
        The custom collection name to add

    Returns
    -------
    CookidooCollection
        The added custom collection

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    json_data = {"title": custom_collection_name}
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("organize:api-custom-list").format(
        **self._cfg.localization.__dict__
    )
    result = self._ensure_mapping(
        await self._request_json(
            "post",
            url,
            "add custom collection",
            json=json_data,
            headers={"ACCEPT": CUSTOM_COLLECTIONS_PATH_ACCEPT},
        ),
        "add custom collection",
    )
    return self._parse_result(
        "loading added custom collection",
        lambda: cookidoo_collection_from_json(
            cast(CustomCollectionJSON, result["content"])
        ),
    )

remove_custom_collection async

Remove custom collection.

Parameters:

Name Type Description Default
custom_collection_id str

The custom collection id to remove

required

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def remove_custom_collection(
    self,
    custom_collection_id: str,
) -> None:
    """Remove custom collection.

    Parameters
    ----------
    custom_collection_id
        The custom collection id to remove

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("organize:api-custom-list-modify").format(
        **self._cfg.localization.__dict__, id=custom_collection_id
    )
    await self._request_json(
        "delete",
        url,
        "remove custom collection",
        headers={"ACCEPT": CUSTOM_COLLECTIONS_PATH_ACCEPT},
        parse_response=False,
    )

add_recipes_to_custom_collection async

Add recipes to a custom collections.

Parameters:

Name Type Description Default
custom_collection_id str

The custom collection to add the recipes to

required
recipe_ids list[str]

The recipe ids to add to a custom collection

required

Returns:

Type Description
CookidooCollection

The changed custom collection

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def add_recipes_to_custom_collection(
    self,
    custom_collection_id: str,
    recipe_ids: list[str],
) -> CookidooCollection:
    """Add recipes to a custom collections.

    Parameters
    ----------
    custom_collection_id
        The custom collection to add the recipes to
    recipe_ids
        The recipe ids to add to a custom collection

    Returns
    -------
    CookidooCollection
        The changed custom collection

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    json_data = {"recipeIds": recipe_ids}
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("organize:api-custom-list-modify").format(
        **self._cfg.localization.__dict__, id=custom_collection_id
    )
    result = self._ensure_mapping(
        await self._request_json(
            "put", url, "add recipes to custom collection", json=json_data
        ),
        "add recipes to custom collection",
    )
    return self._parse_result(
        "loading added recipes",
        lambda: cookidoo_collection_from_json(
            cast(CustomCollectionJSON, result["content"])
        ),
    )

remove_recipe_from_custom_collection async

Remove recipe from a custom collections.

Parameters:

Name Type Description Default
custom_collection_id str

The custom collection to remove the recipe from

required
recipe_id str

The recipe id to remove from a custom collection

required

Returns:

Type Description
CookidooCollection

The changed custom collection

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def remove_recipe_from_custom_collection(
    self,
    custom_collection_id: str,
    recipe_id: str,
) -> CookidooCollection:
    """Remove recipe from a custom collections.

    Parameters
    ----------
    custom_collection_id
        The custom collection to remove the recipe from
    recipe_id
        The recipe id to remove from a custom collection

    Returns
    -------
    CookidooCollection
        The changed custom collection

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("organize:api-custom-list-recipe").format(
        **self._cfg.localization.__dict__,
        id=custom_collection_id,
        recipe=recipe_id,
    )
    result = self._ensure_mapping(
        await self._request_json(
            "delete", url, "remove recipe from custom collection"
        ),
        "remove recipe from custom collection",
    )
    return self._parse_result(
        "loading removed recipe",
        lambda: cookidoo_collection_from_json(
            cast(CustomCollectionJSON, result["content"])
        ),
    )

get_recipes_in_calendar_week async

Get recipes in a calendar week.

Parameters:

Name Type Description Default
day date

The date specifying the calendar week

required

Returns:

Type Description
list[CookidooCalendarDay]

The list of the calendar days with recipes

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def get_recipes_in_calendar_week(
    self, day: date
) -> list[CookidooCalendarDay]:
    """Get recipes in a calendar week.

    Parameters
    ----------
    day
        The date specifying the calendar week

    Returns
    -------
    list[CookidooCalendarDay]
        The list of the calendar days with recipes

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """

    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("planning:api-my-week-from-date").format(
        **self._cfg.localization.__dict__, day=day.isoformat()
    )
    result = self._ensure_mapping(
        await self._request_json("get", url, "loading recipes in calendar week"),
        "loading recipes in calendar week",
    )
    return self._parse_result(
        "loading recipes in calendar week",
        lambda: [
            cookidoo_calendar_day_from_json(
                cast(CalendarDayJSON, calendar_day), self._cfg.localization
            )
            for calendar_day in cast(Sequence[object], result["myDays"])
        ],
    )

add_recipes_to_calendar async

Add recipes to a calendar.

Parameters:

Name Type Description Default
day date

The date to add the recipes to in the calendar

required
recipe_ids list[str]

The recipe ids to add to the calendar

required

Returns:

Type Description
CookidooCalendarDay

The changed calendar day

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def add_recipes_to_calendar(
    self,
    day: date,
    recipe_ids: list[str],
) -> CookidooCalendarDay:
    """Add recipes to a calendar.

    Parameters
    ----------
    day
        The date to add the recipes to in the calendar
    recipe_ids
        The recipe ids to add to the calendar

    Returns
    -------
    CookidooCalendarDay
        The changed calendar day

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    json_data = {"recipeIds": recipe_ids, "dayKey": day.isoformat()}
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("planning:api-my-day").format(
        **self._cfg.localization.__dict__
    )
    result = self._ensure_mapping(
        await self._request_json(
            "put", url, "add recipes to calendar", json=json_data
        ),
        "add recipes to calendar",
    )
    return self._parse_result(
        "loading added recipes",
        lambda: cookidoo_calendar_day_from_json(
            cast(CalendarDayJSON, result["content"]),
            self._cfg.localization,
        ),
    )

remove_recipe_from_calendar async

Remove recipe from calendar.

Parameters:

Name Type Description Default
day date

The date to remove the recipe from in the calendar

required
recipe_id str

The recipe id to remove from the calendar

required

Returns:

Type Description
CookidooCalendarDay

The changed calendar day

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def remove_recipe_from_calendar(
    self,
    day: date,
    recipe_id: str,
) -> CookidooCalendarDay:
    """Remove recipe from calendar.

    Parameters
    ----------
    day
        The date to remove the recipe from in the calendar
    recipe_id
        The recipe id to remove from the calendar

    Returns
    -------
    CookidooCalendarDay
        The changed calendar day

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("planning:api-my-day-recipes").format(
        **self._cfg.localization.__dict__,
        day=day.isoformat(),
        recipe=recipe_id,
    )
    result = self._ensure_mapping(
        await self._request_json("delete", url, "remove recipe from calendar"),
        "remove recipe from calendar",
    )
    if result.get("content") is None:
        # The API returns a null content when the removed recipe was the
        # last one for the day, since the (now empty) day no longer
        # exists as an entity.
        return self._empty_calendar_day(day)
    return self._parse_result(
        "loading removed recipe",
        lambda: cookidoo_calendar_day_from_json(
            cast(CalendarDayJSON, result["content"]),
            self._cfg.localization,
        ),
    )

add_custom_recipes_to_calendar async

Add custom recipes to a calendar.

Parameters:

Name Type Description Default
day date

The date to add the custom recipes to in the calendar

required
recipe_ids list[str]

The recipe ids to add to the calendar

required

Returns:

Type Description
CookidooCalendarDay

The changed calendar day

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def add_custom_recipes_to_calendar(
    self,
    day: date,
    recipe_ids: list[str],
) -> CookidooCalendarDay:
    """Add custom recipes to a calendar.

    Parameters
    ----------
    day
        The date to add the custom recipes to in the calendar
    recipe_ids
        The recipe ids to add to the calendar

    Returns
    -------
    CookidooCalendarDay
        The changed calendar day

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    json_data = {
        "recipeIds": recipe_ids,
        "dayKey": day.isoformat(),
        "recipeSource": "CUSTOMER",
    }
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("planning:api-my-day").format(
        **self._cfg.localization.__dict__
    )
    result = self._ensure_mapping(
        await self._request_json(
            "put", url, "add custom recipes to calendar", json=json_data
        ),
        "add custom recipes to calendar",
    )
    return self._parse_result(
        "loading added custom recipes",
        lambda: cookidoo_calendar_day_from_json(
            cast(CalendarDayJSON, result["content"]),
            self._cfg.localization,
        ),
    )

remove_custom_recipe_from_calendar async

Remove custom recipe from calendar.

Parameters:

Name Type Description Default
day date

The date to remove the custom recipe from in the calendar

required
recipe_id str

The custom recipe id to remove from the calendar

required

Returns:

Type Description
CookidooCalendarDay

The changed calendar day

Raises:

Type Description
CookidooAuthException

When the access token is not valid anymore

CookidooRequestException

If the request fails.

CookidooParseException

If the parsing of the request response fails.

Source code in cookidoo_api/cookidoo.py
async def remove_custom_recipe_from_calendar(
    self,
    day: date,
    recipe_id: str,
) -> CookidooCalendarDay:
    """Remove custom recipe from calendar.

    Parameters
    ----------
    day
        The date to remove the custom recipe from in the calendar
    recipe_id
        The custom recipe id to remove from the calendar

    Returns
    -------
    CookidooCalendarDay
        The changed calendar day

    Raises
    ------
    CookidooAuthException
        When the access token is not valid anymore
    CookidooRequestException
        If the request fails.
    CookidooParseException
        If the parsing of the request response fails.

    """
    await self._ensure_endpoints()
    url = self.api_endpoint / self._path("planning:api-my-day-recipes").format(
        **self._cfg.localization.__dict__,
        day=day.isoformat(),
        recipe=recipe_id,
    )
    result = self._ensure_mapping(
        await self._request_json(
            "delete",
            url,
            "remove custom recipe from calendar",
            params={"recipeSource": "CUSTOMER"},
        ),
        "remove custom recipe from calendar",
    )
    if result.get("content") is None:
        # The API returns a null content when the removed recipe was the
        # last one for the day, since the (now empty) day no longer
        # exists as an entity.
        return self._empty_calendar_day(day)
    return self._parse_result(
        "loading custom removed recipe",
        lambda: cookidoo_calendar_day_from_json(
            cast(CalendarDayJSON, result["content"]),
            self._cfg.localization,
        ),
    )

CookidooAuthException

Bases: CookidooException

When an authentication error is encountered.

CookidooConfigException

Bases: CookidooException

When the config is invalid.

CookidooException

Bases: Exception

General exception occurred.

CookidooParseException

Bases: CookidooException

When data could not be parsed.

CookidooRequestException

Bases: CookidooException

When a request returns an error.

CookidooResponseException

Bases: CookidooException

When a response could not be parsed.

CookidooUnavailableException

Bases: CookidooException

When the network or server is not available.

CookidooAdditionalItem dataclass

Bases: CookidooItem

Cookidoo additional item type.

CookidooAuthData dataclass

OAuth2 tokens obtained from a login, for persistence and restore.

expires_at is a POSIX timestamp (seconds) for the access token.

CookidooCategory dataclass

Cookidoo category type.

Attributes:

Name Type Description
id str

The id of the category

name str

The label of the category

notes str

The additional information of the category

CookidooChapter dataclass

Cookidoo chapter type.

Attributes:

Name Type Description
title

The title of the chapter

recipes list[CookidooChapterRecipe]

The recipes in the chapter

CookidooChapterRecipe dataclass

Cookidoo chapter recipe type.

Attributes:

Name Type Description
id str

The id of the recipe

name str

The label of the recipe

total_time int

The time for the recipe

CookidooCollection dataclass

Cookidoo collection type.

Attributes:

Name Type Description
id str

The id of the collection

title

The title of the collection

description str | None

The description of the collection

chapters list[CookidooChapter]

The recipes in the collection

CookidooConfig dataclass

Cookidoo config type.

Attributes:

Name Type Description
localization CookidooLocalizationConfig

The localization for the api including country, language and url

email str

The email to login

password str

The password to login

client_id str

The OAuth2 client id to run the login flow as

redirect_uri str

The OAuth2 redirect uri registered for client_id

The login runs as a public client (authorization code + PKCE, no client
secret), so both values are public identifiers rather than credentials and
they default to the ones of the Cookidoo mobile app. Callers do not need to
set them; see ``docs/oauth-client.md``.

CookidooCookingActivity dataclass

Live cook state pushed by an appliance's remote monitoring.

Values the recipe does not provide are None (the app renders "---" for an unset current temperature, which is normalised to None here).

is_active property

Whether a cook is currently running or paused.

CookidooCookState

Bases: StrEnum

State of an ongoing remote-monitored cook.

CookidooDevice dataclass

A paired Thermomix appliance on the account.

CookidooIngredient dataclass

Cookidoo ingredient type.

Attributes:

Name Type Description
id str

The id of the ingredient

name str

The label of the ingredient

description str

The description of the item, including the quantity or other helpful information

CookidooIngredientItem dataclass

Bases: CookidooItem

Cookidoo ingredient item type.

Attributes:

Name Type Description
description str

The description of the item, including the quantity or other helpful information

CookidooItem dataclass

Cookidoo item type.

Attributes:

Name Type Description
id str

The id of the item

name str

The label of the item

CookidooLocalizationConfig dataclass

A localization config class.

CookidooRecipeCollection dataclass

Cookidoo recipe collection type.

Attributes:

Name Type Description
id str

The id of the collection

name str

The label of the collection

additional_information

The additional information of the collection

CookidooSearchRecipeHit dataclass

A single recipe hit from Cookidoo search.

Attributes:

Name Type Description
id str

The id of the recipe

name str

The title of the recipe

thumbnail str | None

The thumbnail image URL (small preview)

image str | None

The full-size image URL

url str

The URL of the recipe

CookidooSearchResult dataclass

Cookidoo search result type.

Attributes:

Name Type Description
recipes list[CookidooSearchRecipeHit]

List of recipe hits matching the search

total int

Total number of matching recipes

CookidooShoppingRecipe dataclass

Cookidoo shopping recipe type.

Attributes:

Name Type Description
id str

The id of the recipe

name str

The label of the recipe

ingredients list[CookidooIngredient]

The ingredients of the recipe

thumbnail str | None

The thumbnail image URL (small preview)

image str | None

The full-size image URL

url str

The URL of the recipe

CookidooShoppingRecipeDetails dataclass

Bases: CookidooShoppingRecipe

Cookidoo recipe details type.

Attributes:

Name Type Description
difficulty str

The difficulty of the recipe

notes list[str]

Hints and additional information about the recipe

categories list[CookidooCategory]

The categories of the recipe

collections list[CookidooRecipeCollection]

The collections of the recipe

utensils list[str]

The utensils needed for the recipe

serving_size int

The service size of the recipe

active_time int

The time needed preparing the recipe [in seconds]

total_time int

The time needed until the recipe is ready [in seconds]

nutrition_groups list[CookidooNutritionGroup]

The nutrition groups of the recipe (from API, may be empty)

step_groups list[CookidooRecipeStepGroup]

The grouped cooking instructions for the recipe (from API, may be empty). Instruction text is returned as HTML markup, as sent by the API.

CookidooSubscription dataclass

A subscription class.

CookidooUserInfo dataclass

A user info class.

ThermomixMachineType

Bases: StrEnum

Thermomix machine types.

cooking_activity_from_push

Convert a remote-monitoring push payload into a cooking activity.

Appliance state is delivered out of band (a Firebase Cloud Messaging data message) rather than as an HTTP response, so consumers receive it via their own push channel and decode it here. Both the on-the-wire field names (leadingText/trailingText/completedDate/staleDate/…) and the app's parsed names are accepted.

Source code in cookidoo_api/helpers.py
def cooking_activity_from_push(
    data: Mapping[str, object],
) -> CookidooCookingActivity:
    """Convert a remote-monitoring push payload into a cooking activity.

    Appliance state is delivered out of band (a Firebase Cloud Messaging data
    message) rather than as an HTTP response, so consumers receive it via their
    own push channel and decode it here. Both the on-the-wire field names
    (``leadingText``/``trailingText``/``completedDate``/``staleDate``/…) and the
    app's parsed names are accepted.
    """

    def first(*keys: str) -> object:
        for key in keys:
            if key in data and data[key] is not None:
                return data[key]
        return None

    remaining_raw = first("remainingDuration")
    remaining: int | None = None
    if isinstance(remaining_raw, (int, str)):
        try:
            remaining = int(remaining_raw)
        except ValueError:
            remaining = None
    completed_at = _push_timestamp(first("completedDate", "completedTimestamp"))
    end_at = _push_timestamp(first("endTimestamp"))
    # The wire payload has no remainingDuration; derive it from the finish time.
    if remaining is None:
        finish = completed_at or end_at
        if finish is not None:
            remaining = max(0, int((finish - datetime.now(UTC)).total_seconds()))

    state_raw = first("state")
    state = CookidooCookState(str(state_raw).upper()) if state_raw is not None else None
    recipe_type = first("recipeType")

    return CookidooCookingActivity(
        device_id=str(first("deviceId") or ""),
        cooking_activity_id=cast("str | None", first("cookingActivityId")),
        state=state,
        recipe_id=cast("str | None", first("recipeId")),
        recipe_type=str(recipe_type).upper() if recipe_type is not None else None,
        recipe_name=cast(
            "str | None", first("leadingText", "leadingInfoText", "infoText")
        ),
        step=cast("str | None", first("trailingText", "trailingInfoText")),
        remaining_seconds=remaining,
        is_time_estimated=_push_bool(data.get("isTimeEstimated", False)),
        current_temperature=_push_number(first("primaryInfo")),
        target_temperature=_push_number(first("secondaryInfo")),
        message_title=cast("str | None", first("messageTitle")),
        message_body=cast("str | None", first("messageBody")),
        message_criticality=cast("str | None", first("messageCriticality")),
        completed_at=completed_at,
        stale_at=_push_timestamp(first("staleDate", "staleTimestamp")),
    )

get_country_options async

Get a list of possible country options.

Source code in cookidoo_api/helpers.py
async def get_country_options() -> list[str]:
    """Get a list of possible country options."""
    return list({option.country_code for option in await get_localization_options()})

get_language_options async

Get a list of possible language options.

Source code in cookidoo_api/helpers.py
async def get_language_options() -> list[str]:
    """Get a list of possible language options."""
    return list({option.language for option in await get_localization_options()})

get_localization_options async

Get a list of possible localization options.

Source code in cookidoo_api/helpers.py
async def get_localization_options(
    country: str | None = None,
    language: str | None = None,
) -> list[CookidooLocalizationConfig]:
    """Get a list of possible localization options."""
    return await __get_localization_options(country, language)