"""Networks API endpoints.

This file is automatically @generated from the Meraki API specification.
Do not edit this file manually.

"""

from __future__ import annotations

import urllib.parse
from typing import TYPE_CHECKING, Any, Literal

from meraki_client.schemas import (
    BatchNetworkFloorPlansAutoLocateJobsJobsItem,
    BatchNetworkFloorPlansAutoLocateJobsResponse,
    BatchNetworkFloorPlansDevicesUpdateAssignmentsItem,
    BatchNetworkFloorPlansDevicesUpdateResponse,
    BindNetworkResponse,
    ClaimNetworkDevicesDetailsByDeviceItem,
    ClaimNetworkDevicesResponse,
    CreateNetworkFirmwareUpgradesRollbackReasonsItem,
    CreateNetworkFirmwareUpgradesRollbackResponse,
    CreateNetworkFirmwareUpgradesRollbackToVersion,
    CreateNetworkFirmwareUpgradesStagedEventProducts,
    CreateNetworkFirmwareUpgradesStagedEventResponse,
    CreateNetworkFirmwareUpgradesStagedEventStagesItem,
    CreateNetworkFirmwareUpgradesStagedGroupAssignedDevices,
    CreateNetworkFirmwareUpgradesStagedGroupResponse,
    CreateNetworkFloorPlanBottomLeftCorner,
    CreateNetworkFloorPlanBottomRightCorner,
    CreateNetworkFloorPlanCenter,
    CreateNetworkFloorPlanResponse,
    CreateNetworkFloorPlanTopLeftCorner,
    CreateNetworkFloorPlanTopRightCorner,
    CreateNetworkGroupPolicyBandwidth,
    CreateNetworkGroupPolicyBonjourForwarding,
    CreateNetworkGroupPolicyContentFiltering,
    CreateNetworkGroupPolicyFirewallAndTrafficShaping,
    CreateNetworkGroupPolicyResponse,
    CreateNetworkGroupPolicyScheduling,
    CreateNetworkGroupPolicyVlanTagging,
    CreateNetworkMerakiAuthUserAuthorizationsItem,
    CreateNetworkMerakiAuthUserResponse,
    CreateNetworkMqttBrokerAuthentication,
    CreateNetworkMqttBrokerResponse,
    CreateNetworkMqttBrokerSecurity,
    CreateNetworkPiiRequestResponse,
    CreateNetworkVlanProfileResponse,
    CreateNetworkVlanProfileVlanGroupsItem,
    CreateNetworkVlanProfileVlanNamesItem,
    CreateNetworkWebhooksHttpServerPayloadTemplate,
    CreateNetworkWebhooksHttpServerResponse,
    CreateNetworkWebhooksPayloadTemplateHeadersItem,
    CreateNetworkWebhooksPayloadTemplateResponse,
    CreateNetworkWebhooksWebhookTestResponse,
    DeferNetworkFirmwareUpgradesStagedEventsResponse,
    DictResponse,
    GetNetworkAlertsHistoryResponseItem,
    GetNetworkAlertsSettingsResponse,
    GetNetworkBluetoothClientResponse,
    GetNetworkBluetoothClientsResponseItem,
    GetNetworkClientPolicyResponse,
    GetNetworkClientResponse,
    GetNetworkClientsApplicationUsageResponseItem,
    GetNetworkClientsBandwidthUsageHistoryResponseItem,
    GetNetworkClientsOverviewResponse,
    GetNetworkClientsResponseItem,
    GetNetworkClientsUsageHistoriesResponseItem,
    GetNetworkClientTrafficHistoryResponseItem,
    GetNetworkClientUsageHistoryResponseItem,
    GetNetworkDevicesResponseItem,
    GetNetworkEventsEventTypesResponseItem,
    GetNetworkEventsResponseEventsItem,
    GetNetworkFirmwareUpgradesResponse,
    GetNetworkFirmwareUpgradesStagedEventsResponse,
    GetNetworkFirmwareUpgradesStagedGroupResponse,
    GetNetworkFirmwareUpgradesStagedGroupsResponseItem,
    GetNetworkFirmwareUpgradesStagedStagesResponseItem,
    GetNetworkFloorPlanResponse,
    GetNetworkFloorPlansResponseItem,
    GetNetworkGroupPoliciesResponseItem,
    GetNetworkGroupPolicyResponse,
    GetNetworkHealthAlertsResponseItem,
    GetNetworkMerakiAuthUserResponse,
    GetNetworkMerakiAuthUsersResponseItem,
    GetNetworkMqttBrokerResponse,
    GetNetworkMqttBrokersResponseItem,
    GetNetworkNetflowResponse,
    GetNetworkNetworkHealthChannelUtilizationResponseItem,
    GetNetworkPiiPiiKeysResponse,
    GetNetworkPiiRequestResponse,
    GetNetworkPiiRequestsResponseItem,
    GetNetworkPiiSmDevicesForKeyResponse,
    GetNetworkPiiSmOwnersForKeyResponse,
    GetNetworkPoliciesByClientResponseItem,
    GetNetworkResponse,
    GetNetworkSettingsResponse,
    GetNetworkSnmpResponse,
    GetNetworkSplashLoginAttemptsResponseItem,
    GetNetworkSyslogServersResponse,
    GetNetworkTopologyLinkLayerResponse,
    GetNetworkTrafficAnalysisResponse,
    GetNetworkTrafficResponseItem,
    GetNetworkTrafficShapingDscpTaggingOptionsResponse,
    GetNetworkVlanProfileResponse,
    GetNetworkVlanProfilesAssignmentsByDeviceResponseItem,
    GetNetworkVlanProfilesResponseItem,
    GetNetworkWebhooksHttpServerResponse,
    GetNetworkWebhooksHttpServersResponseItem,
    GetNetworkWebhooksPayloadTemplateResponse,
    GetNetworkWebhooksPayloadTemplatesResponseItem,
    GetNetworkWebhooksWebhookTestResponse,
    ProvisionNetworkClientsClientsItem,
    ProvisionNetworkClientsPoliciesBySecurityAppliance,
    ProvisionNetworkClientsPoliciesBySsid,
    ProvisionNetworkClientsResponse,
    PublishNetworkFloorPlansAutoLocateJobDevicesItem,
    PublishNetworkFloorPlansAutoLocateJobResponse,
    ReassignNetworkVlanProfilesAssignmentsResponse,
    ReassignNetworkVlanProfilesAssignmentsVlanProfile,
    RecalculateNetworkFloorPlansAutoLocateJobDevicesItem,
    RecalculateNetworkFloorPlansAutoLocateJobResponse,
    RollbacksNetworkFirmwareUpgradesStagedEventsReasonsItem,
    RollbacksNetworkFirmwareUpgradesStagedEventsResponse,
    RollbacksNetworkFirmwareUpgradesStagedEventsStagesItem,
    SplitNetworkResponse,
    UnbindNetworkResponse,
    UpdateNetworkAlertsSettingsAlertsItem,
    UpdateNetworkAlertsSettingsDefaultDestinations,
    UpdateNetworkAlertsSettingsMuting,
    UpdateNetworkAlertsSettingsResponse,
    UpdateNetworkClientPolicyResponse,
    UpdateNetworkClientSplashAuthorizationStatusSsids,
    UpdateNetworkFirmwareUpgradesProducts,
    UpdateNetworkFirmwareUpgradesResponse,
    UpdateNetworkFirmwareUpgradesStagedEventsResponse,
    UpdateNetworkFirmwareUpgradesStagedEventsStagesItem,
    UpdateNetworkFirmwareUpgradesStagedGroupAssignedDevices,
    UpdateNetworkFirmwareUpgradesStagedGroupResponse,
    UpdateNetworkFirmwareUpgradesStagedStagesJsonItem,
    UpdateNetworkFirmwareUpgradesStagedStagesResponse,
    UpdateNetworkFirmwareUpgradesUpgradeWindow,
    UpdateNetworkFloorPlanBottomLeftCorner,
    UpdateNetworkFloorPlanBottomRightCorner,
    UpdateNetworkFloorPlanCenter,
    UpdateNetworkFloorPlanResponse,
    UpdateNetworkFloorPlanTopLeftCorner,
    UpdateNetworkFloorPlanTopRightCorner,
    UpdateNetworkGroupPolicyBandwidth,
    UpdateNetworkGroupPolicyBonjourForwarding,
    UpdateNetworkGroupPolicyContentFiltering,
    UpdateNetworkGroupPolicyFirewallAndTrafficShaping,
    UpdateNetworkGroupPolicyResponse,
    UpdateNetworkGroupPolicyScheduling,
    UpdateNetworkGroupPolicyVlanTagging,
    UpdateNetworkMerakiAuthUserAuthorizationsItem,
    UpdateNetworkMerakiAuthUserResponse,
    UpdateNetworkMqttBrokerAuthentication,
    UpdateNetworkMqttBrokerResponse,
    UpdateNetworkMqttBrokerSecurity,
    UpdateNetworkNetflowResponse,
    UpdateNetworkResponse,
    UpdateNetworkSettingsLocalStatusPage,
    UpdateNetworkSettingsNamedVlans,
    UpdateNetworkSettingsResponse,
    UpdateNetworkSettingsSecurePort,
    UpdateNetworkSnmpResponse,
    UpdateNetworkSnmpUsersItem,
    UpdateNetworkSyslogServersResponse,
    UpdateNetworkSyslogServersServersItem,
    UpdateNetworkTrafficAnalysisCustomPieChartItemsItem,
    UpdateNetworkTrafficAnalysisResponse,
    UpdateNetworkVlanProfileResponse,
    UpdateNetworkVlanProfileVlanGroupsItem,
    UpdateNetworkVlanProfileVlanNamesItem,
    UpdateNetworkWebhooksHttpServerPayloadTemplate,
    UpdateNetworkWebhooksHttpServerResponse,
    UpdateNetworkWebhooksPayloadTemplateHeadersItem,
    UpdateNetworkWebhooksPayloadTemplateResponse,
    VmxNetworkDevicesClaimResponse,
)
from meraki_client.types import (
    CreateNetworkFirmwareUpgradesRollbackProduct,
    CreateNetworkGroupPolicySplashAuthSettings,
    CreateNetworkMerakiAuthUserAccountType,
    CreateNetworkPiiRequestType,
    GetNetworkClientsApplicationUsageSsidNumber,
    GetNetworkClientsRecentDeviceConnections,
    GetNetworkClientsStatuses,
    GetNetworkClientsUsageHistoriesSsidNumber,
    GetNetworkEventsProductType,
    GetNetworkSplashLoginAttemptsSsidNumber,
    GetNetworkTrafficDeviceType,
    GetNetworkVlanProfilesAssignmentsByDeviceProductTypes,
    ProvisionNetworkClientsDevicePolicy,
    UpdateNetworkGroupPolicySplashAuthSettings,
    UpdateNetworkSnmpAccess,
    UpdateNetworkTrafficAnalysisMode,
    VmxNetworkDevicesClaimSize,
)

if TYPE_CHECKING:
    from meraki_client.aio._session import AsyncPaginatedResponse, Session


class Networks:
    """Networks class."""

    def __init__(self, session: Session) -> None:
        self._session = session

    async def get_network(self, network_id: str) -> GetNetworkResponse:
        """Return a network.

        [API documentation: getNetwork](https://developer.cisco.com/meraki/api-v1/#!get-network)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "id": "N_24329156",
              "organizationId": "2930418",
              "name": "Main Office",
              "productTypes": [
                "appliance",
                "switch",
                "wireless"
              ],
              "timeZone": "America/Los_Angeles",
              "tags": [
                "tag1",
                "tag2"
              ],
              "enrollmentString": "my-enrollment-string",
              "url": "https://n1.meraki.com//n//manage/nodes/list",
              "notes": "Additional description of the network",
              "isBoundToConfigTemplate": false
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}"

        return await self._session.get(
            scope="networks",
            operation_id="getNetwork",
            path=path,
            response_schema=GetNetworkResponse,
        )

    async def update_network(
        self,
        network_id: str,
        *,
        name: str | None = None,
        time_zone: str | None = None,
        tags: list[str] | None = None,
        enrollment_string: str | None = None,
        notes: str | None = None,
    ) -> UpdateNetworkResponse:
        """Update a network.

        [API documentation: updateNetwork](https://developer.cisco.com/meraki/api-v1/#!update-network)

        Args:
            network_id: Network ID.
            name: The name of the network.
            time_zone: The timezone of the network. For a list of allowed timezones, please see the
                'TZ' column in the table in <a target='_blank'
                href='https://en.wikipedia.org/wiki/List_of_tz_database_time_zones'>this
                article.</a>.
            tags: A list of tags to be applied to the network.
            enrollment_string: A unique identifier which can be used for device enrollment or easy
                access through the Meraki SM Registration page or the Self Service
                Portal. Please note that changing this field may cause existing
                bookmarks to break.
            notes: Add any notes or additional information about this network here.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "id": "N_24329156",
              "organizationId": "2930418",
              "name": "Main Office",
              "productTypes": [
                "appliance",
                "switch",
                "wireless"
              ],
              "timeZone": "America/Los_Angeles",
              "tags": [
                "tag1",
                "tag2"
              ],
              "enrollmentString": "my-enrollment-string",
              "url": "https://n1.meraki.com//n//manage/nodes/list",
              "notes": "Additional description of the network",
              "isBoundToConfigTemplate": false
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}"

        payload: dict[str, Any] = {}
        if name is not None:
            payload["name"] = name
        if time_zone is not None:
            payload["timeZone"] = time_zone
        if tags is not None:
            payload["tags"] = tags
        if enrollment_string is not None:
            payload["enrollmentString"] = enrollment_string
        if notes is not None:
            payload["notes"] = notes

        return await self._session.put(
            scope="networks",
            operation_id="updateNetwork",
            path=path,
            json=payload,
            response_schema=UpdateNetworkResponse,
        )

    async def delete_network(self, network_id: str) -> None:
        """Delete a network.

        [API documentation: deleteNetwork](https://developer.cisco.com/meraki/api-v1/#!delete-network)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}"

        return await self._session.delete(scope="networks", operation_id="deleteNetwork", path=path)

    def get_network_alerts_history(
        self,
        network_id: str,
        *,
        per_page: int | None = None,
        starting_after: str | None = None,
        ending_before: str | None = None,
        total_pages: int | Literal["all"] = "all",
        direction: Literal["prev", "next"] = "next",
    ) -> AsyncPaginatedResponse[GetNetworkAlertsHistoryResponseItem]:
        """Return the alert history for this network.

        [API documentation: getNetworkAlertsHistory](https://developer.cisco.com/meraki/api-v1/#!get-network-alerts-history)

        Args:
            network_id: Network ID.
            per_page: The number of entries per page returned. Acceptable range is 3 - 1000. Default
                is 100.
            starting_after: A token used by the server to indicate the start of the page. Often this
                is a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            ending_before: A token used by the server to indicate the end of the page. Often this is
                a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            total_pages: use with per_page to get total results up to total_pages * per_page; -1 or
                "all" for all pages.
            direction: direction to paginate, either "next" (default) or "prev" page.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "occurredAt": "2022-07-11T22:35:34Z",
                "alertTypeId": "settings_changed",
                "alertType": "Settings changed",
                "device": {
                  "serial": "Q3CG-G6W8-BEVR"
                },
                "destinations": {
                  "email": {
                    "sentAt": "2022-07-11T22:40:34Z"
                  },
                  "push": {
                    "sentAt": "2022-07-11T22:40:34Z"
                  },
                  "sms": {
                    "sentAt": "2022-07-11T22:40:34Z"
                  },
                  "webhook": {
                    "sentAt": "2022-07-11T22:40:34Z"
                  }
                }
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/alerts/history"

        params: dict[str, Any] = {}
        if per_page is not None:
            params["perPage"] = per_page
        if starting_after is not None:
            params["startingAfter"] = starting_after
        if ending_before is not None:
            params["endingBefore"] = ending_before

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkAlertsHistory",
            path=path,
            params=params,
            total_pages=total_pages,
            direction=direction,
            item_schema=GetNetworkAlertsHistoryResponseItem,
        )

    async def get_network_alerts_settings(
        self, network_id: str
    ) -> GetNetworkAlertsSettingsResponse:
        r"""Return the alert configuration for this network.

        [API documentation: getNetworkAlertsSettings](https://developer.cisco.com/meraki/api-v1/#!get-network-alerts-settings)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "defaultDestinations": {
                "emails": [
                  "miles@meraki.com"
                ],
                "allAdmins": true,
                "snmp": true,
                "httpServerIds": [
                  "aHR0cHM6Ly93d3cuZXhhbXBsZS5jb20vd2ViaG9va3M="
                ]
              },
              "alerts": [
                {
                  "type": "gatewayDown",
                  "enabled": true,
                  "alertDestinations": {
                    "emails": [
                      "miles@meraki.com"
                    ],
                    "smsNumbers": [
                      "+15555555555"
                    ],
                    "allAdmins": false,
                    "snmp": false,
                    "httpServerIds": [
                      "aHR0cHM6Ly93d3cuZXhhbXBsZS5jb20vd2ViaG9va3M="
                    ]
                  },
                  "filters": {
                    "conditions": [
                      {
                        "type": "temperature",
                        "unit": "celsius",
                        "duration": 0,
                        "direction": "+",
                        "threshold": 72.5
                      }
                    ],
                    "failureType": "802.1X auth fail",
                    "lookbackWindow": 360,
                    "minDuration": 60,
                    "name": "Filter",
                    "period": 1800,
                    "priority": "",
                    "regex": "[a-z]",
                    "selector": "{\"smartSensitivity\":\"medium\",\"smartEnabled\":false,\"eventReminderPeriodSecs\":10800}",
                    "serials": [
                      "Q234-ABCD-0001",
                      "Q234-ABCD-0002",
                      "Q234-ABCD-0003"
                    ],
                    "ssidNum": 1,
                    "tag": "tag1",
                    "threshold": 30,
                    "timeout": 60
                  }
                }
              ],
              "muting": {
                "byPortSchedules": {
                  "enabled": true
                }
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/alerts/settings"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkAlertsSettings",
            path=path,
            response_schema=GetNetworkAlertsSettingsResponse,
        )

    async def update_network_alerts_settings(
        self,
        network_id: str,
        *,
        default_destinations: UpdateNetworkAlertsSettingsDefaultDestinations | None = None,
        alerts: list[UpdateNetworkAlertsSettingsAlertsItem] | None = None,
        muting: UpdateNetworkAlertsSettingsMuting | None = None,
    ) -> UpdateNetworkAlertsSettingsResponse:
        r"""Update the alert configuration for this network.

        [API documentation: updateNetworkAlertsSettings](https://developer.cisco.com/meraki/api-v1/#!update-network-alerts-settings)

        Args:
            network_id: Network ID.
            default_destinations: The network-wide destinations for all alerts on the network.
            alerts: Alert-specific configuration for each type. Only alerts that pertain to the
                network can be updated.
            muting: Mute alerts under certain conditions.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "defaultDestinations": {
                "emails": [
                  "miles@meraki.com"
                ],
                "allAdmins": true,
                "snmp": true,
                "httpServerIds": [
                  "aHR0cHM6Ly93d3cuZXhhbXBsZS5jb20vd2ViaG9va3M="
                ]
              },
              "alerts": [
                {
                  "type": "gatewayDown",
                  "enabled": true,
                  "alertDestinations": {
                    "emails": [
                      "miles@meraki.com"
                    ],
                    "smsNumbers": [
                      "+15555555555"
                    ],
                    "allAdmins": false,
                    "snmp": false,
                    "httpServerIds": [
                      "aHR0cHM6Ly93d3cuZXhhbXBsZS5jb20vd2ViaG9va3M="
                    ]
                  },
                  "filters": {
                    "conditions": [
                      {
                        "type": "temperature",
                        "unit": "celsius",
                        "duration": 0,
                        "direction": "+",
                        "threshold": 72.5
                      }
                    ],
                    "failureType": "802.1X auth fail",
                    "lookbackWindow": 360,
                    "minDuration": 60,
                    "name": "Filter",
                    "period": 1800,
                    "priority": "",
                    "regex": "[a-z]",
                    "selector": "{\"smartSensitivity\":\"medium\",\"smartEnabled\":false,\"eventReminderPeriodSecs\":10800}",
                    "serials": [
                      "Q234-ABCD-0001",
                      "Q234-ABCD-0002",
                      "Q234-ABCD-0003"
                    ],
                    "ssidNum": 1,
                    "tag": "tag1",
                    "threshold": 30,
                    "timeout": 60
                  }
                }
              ],
              "muting": {
                "byPortSchedules": {
                  "enabled": true
                }
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/alerts/settings"

        payload: dict[str, Any] = {}
        if default_destinations is not None:
            payload["defaultDestinations"] = default_destinations.model_dump(
                by_alias=True, exclude_none=True
            )
        if alerts is not None:
            payload["alerts"] = [
                item.model_dump(by_alias=True, exclude_none=True) for item in alerts
            ]
        if muting is not None:
            payload["muting"] = muting.model_dump(by_alias=True, exclude_none=True)

        return await self._session.put(
            scope="networks",
            operation_id="updateNetworkAlertsSettings",
            path=path,
            json=payload,
            response_schema=UpdateNetworkAlertsSettingsResponse,
        )

    async def bind_network(
        self, *, network_id: str, config_template_id: str, auto_bind: bool | None = None
    ) -> BindNetworkResponse:
        """Bind a network to a template.

        [API documentation: bindNetwork](https://developer.cisco.com/meraki/api-v1/#!bind-network)

        Args:
            network_id: Network ID.
            config_template_id: The ID of the template to which the network should be bound.
            auto_bind: Optional boolean indicating whether the network's switches should
                automatically bind to profiles of the same model. Defaults to false if
                left unspecified. This option only affects switch networks and switch
                templates. Auto-bind is not valid unless the switch template has at
                least one profile and has at most one profile per switch model.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "id": "N_24329156",
              "organizationId": "2930418",
              "name": "Main Office",
              "productTypes": [
                "appliance",
                "switch",
                "wireless"
              ],
              "timeZone": "America/Los_Angeles",
              "tags": [
                "tag1",
                "tag2"
              ],
              "enrollmentString": "my-enrollment-string",
              "url": "https://n1.meraki.com//n//manage/nodes/list",
              "notes": "Additional description of the network",
              "isBoundToConfigTemplate": false,
              "configTemplateId": "N_24329156"
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/bind"

        payload: dict[str, Any] = {}
        if config_template_id is not None:
            payload["configTemplateId"] = config_template_id
        if auto_bind is not None:
            payload["autoBind"] = auto_bind

        return await self._session.post(
            scope="networks",
            operation_id="bindNetwork",
            path=path,
            json=payload,
            response_schema=BindNetworkResponse,
        )

    def get_network_bluetooth_clients(
        self,
        network_id: str,
        *,
        t0: str | None = None,
        timespan: float | None = None,
        per_page: int | None = None,
        starting_after: str | None = None,
        ending_before: str | None = None,
        include_connectivity_history: bool | None = None,
        total_pages: int | Literal["all"] = "all",
        direction: Literal["prev", "next"] = "next",
    ) -> AsyncPaginatedResponse[GetNetworkBluetoothClientsResponseItem]:
        """List the Bluetooth clients seen by APs in this network.

        [API documentation: getNetworkBluetoothClients](https://developer.cisco.com/meraki/api-v1/#!get-network-bluetooth-clients)

        Args:
            network_id: Network ID.
            t0: The beginning of the timespan for the data. The maximum lookback period is 7 days
                from today.
            timespan: The timespan for which the information will be fetched. If specifying
                timespan, do not specify parameter t0. The value must be in seconds and
                be less than or equal to 7 days. The default is 1 day.
            per_page: The number of entries per page returned. Acceptable range is 5 - 1000. Default
                is 10.
            starting_after: A token used by the server to indicate the start of the page. Often this
                is a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            ending_before: A token used by the server to indicate the end of the page. Often this is
                a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            include_connectivity_history: Include the connectivity history for this client.
            total_pages: use with per_page to get total results up to total_pages * per_page; -1 or
                "all" for all pages.
            direction: direction to paginate, either "next" (default) or "prev" page.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "id": "1284392014819",
                "mac": "22:33:44:55:66:77",
                "networkId": "N_24329156",
                "name": "My Device",
                "deviceName": "Bose QuietComfort 35",
                "manufacturer": "Bose",
                "lastSeen": 1526087474,
                "seenByDeviceMac": "00:11:22:33:44:55",
                "inSightAlert": false,
                "outOfSightAlert": false,
                "tags": [
                  "tag1",
                  "tag2"
                ]
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/bluetoothClients"

        params: dict[str, Any] = {}
        if t0 is not None:
            params["t0"] = t0
        if timespan is not None:
            params["timespan"] = timespan
        if per_page is not None:
            params["perPage"] = per_page
        if starting_after is not None:
            params["startingAfter"] = starting_after
        if ending_before is not None:
            params["endingBefore"] = ending_before
        if include_connectivity_history is not None:
            params["includeConnectivityHistory"] = include_connectivity_history

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkBluetoothClients",
            path=path,
            params=params,
            total_pages=total_pages,
            direction=direction,
            item_schema=GetNetworkBluetoothClientsResponseItem,
        )

    async def get_network_bluetooth_client(
        self,
        *,
        network_id: str,
        bluetooth_client_id: str,
        include_connectivity_history: bool | None = None,
        connectivity_history_timespan: int | None = None,
    ) -> GetNetworkBluetoothClientResponse:
        """Return a Bluetooth client.

        [API documentation: getNetworkBluetoothClient](https://developer.cisco.com/meraki/api-v1/#!get-network-bluetooth-client)

        Args:
            network_id: Network ID.
            bluetooth_client_id: Bluetooth client ID.
            include_connectivity_history: Include the connectivity history for this client.
            connectivity_history_timespan: The timespan, in seconds, for the connectivityHistory
                data. By default 1 day, 86400, will be used.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "id": "1284392014819",
              "mac": "22:33:44:55:66:77",
              "networkId": "N_24329156",
              "name": "My Device",
              "deviceName": "Bose QuietComfort 35",
              "manufacturer": "Bose",
              "lastSeen": 1526087474,
              "seenByDeviceMac": "00:11:22:33:44:55",
              "inSightAlert": false,
              "outOfSightAlert": false,
              "tags": [
                "tag1",
                "tag2"
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        bluetooth_client_id = urllib.parse.quote(str(bluetooth_client_id), safe="")
        path = f"/networks/{network_id}/bluetoothClients/{bluetooth_client_id}"

        params: dict[str, Any] = {}
        if include_connectivity_history is not None:
            params["includeConnectivityHistory"] = include_connectivity_history
        if connectivity_history_timespan is not None:
            params["connectivityHistoryTimespan"] = connectivity_history_timespan

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkBluetoothClient",
            path=path,
            params=params,
            response_schema=GetNetworkBluetoothClientResponse,
        )

    def get_network_clients(
        self,
        network_id: str,
        *,
        t0: str | None = None,
        timespan: float | None = None,
        per_page: int | None = None,
        starting_after: str | None = None,
        ending_before: str | None = None,
        statuses: GetNetworkClientsStatuses | None = None,
        ip: str | None = None,
        ip6: str | None = None,
        ip6_local: str | None = None,
        mac: str | None = None,
        os: str | None = None,
        psk_group: str | None = None,
        description: str | None = None,
        vlan: str | None = None,
        named_vlan: str | None = None,
        recent_device_connections: GetNetworkClientsRecentDeviceConnections | None = None,
        total_pages: int | Literal["all"] = "all",
        direction: Literal["prev", "next"] = "next",
    ) -> AsyncPaginatedResponse[GetNetworkClientsResponseItem]:
        """List the clients that have used this network in the timespan.

        [API documentation: getNetworkClients](https://developer.cisco.com/meraki/api-v1/#!get-network-clients)

        Args:
            network_id: Network ID.
            t0: The beginning of the timespan for the data. The maximum lookback period is 31 days
                from today.
            timespan: The timespan for which the information will be fetched. If specifying
                timespan, do not specify parameter t0. The value must be in seconds and
                be less than or equal to 31 days. The default is 1 day.
            per_page: The number of entries per page returned. Acceptable range is 3 - 5000. Default
                is 10.
            starting_after: A token used by the server to indicate the start of the page. Often this
                is a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            ending_before: A token used by the server to indicate the end of the page. Often this is
                a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            statuses: Filters clients based on status. Can be one of 'Online' or 'Offline'.
            ip: Filters clients based on a partial or full match for the ip address field.
            ip6: Filters clients based on a partial or full match for the ip6 address field.
            ip6_local: Filters clients based on a partial or full match for the ip6Local address
                field.
            mac: Filters clients based on a partial or full match for the mac address field.
            os: Filters clients based on a partial or full match for the os (operating system)
                field.
            psk_group: Filters clients based on partial or full match for the iPSK name field.
            description: Filters clients based on a partial or full match for the description field.
            vlan: Filters clients based on the full match for the VLAN field.
            named_vlan: Filters clients based on the partial or full match for the named VLAN field.
            recent_device_connections: Filters clients based on recent connection type. Can be one
                of 'Wired' or 'Wireless'.
            total_pages: use with per_page to get total results up to total_pages * per_page; -1 or
                "all" for all pages.
            direction: direction to paginate, either "next" (default) or "prev" page.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "id": "k74272e",
                "mac": "22:33:44:55:66:77",
                "ip": "1.2.3.4",
                "ip6": "2001:db8:3c4d:15::1",
                "description": "Miles's phone",
                "firstSeen": 1518365681,
                "lastSeen": 1526087474,
                "manufacturer": "Apple",
                "os": "iOS",
                "user": "milesmeraki",
                "vlan": "100",
                "ssid": "My SSID",
                "switchport": "My switch port",
                "wirelessCapabilities": "802.11b - 2.4 GHz",
                "smInstalled": true,
                "recentDeviceMac": "22:33:44:55:66:77",
                "status": "Online",
                "usage": {
                  "sent": 138.0,
                  "recv": 61.0
                },
                "namedVlan": "My VLAN",
                "adaptivePolicyGroup": "2: Infrastructure",
                "deviceTypePrediction": "iPhone SE, iOS9.3.5",
                "recentDeviceSerial": "Q234-ABCD-5678",
                "recentDeviceName": "00:11:22:33:44:55",
                "recentDeviceConnection": "Wired",
                "notes": "My AP's note",
                "ip6Local": "fe80:0:0:0:1430:aac1:6826:75ab",
                "groupPolicy8021x": "Student_Access",
                "pskGroup": "Group 1"
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/clients"

        params: dict[str, Any] = {}
        if t0 is not None:
            params["t0"] = t0
        if timespan is not None:
            params["timespan"] = timespan
        if per_page is not None:
            params["perPage"] = per_page
        if starting_after is not None:
            params["startingAfter"] = starting_after
        if ending_before is not None:
            params["endingBefore"] = ending_before
        if statuses is not None:
            params["statuses[]"] = statuses
        if ip is not None:
            params["ip"] = ip
        if ip6 is not None:
            params["ip6"] = ip6
        if ip6_local is not None:
            params["ip6Local"] = ip6_local
        if mac is not None:
            params["mac"] = mac
        if os is not None:
            params["os"] = os
        if psk_group is not None:
            params["pskGroup"] = psk_group
        if description is not None:
            params["description"] = description
        if vlan is not None:
            params["vlan"] = vlan
        if named_vlan is not None:
            params["namedVlan"] = named_vlan
        if recent_device_connections is not None:
            params["recentDeviceConnections[]"] = recent_device_connections

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkClients",
            path=path,
            params=params,
            total_pages=total_pages,
            direction=direction,
            item_schema=GetNetworkClientsResponseItem,
        )

    def get_network_clients_application_usage(
        self,
        *,
        network_id: str,
        clients: str,
        ssid_number: GetNetworkClientsApplicationUsageSsidNumber | None = None,
        per_page: int | None = None,
        starting_after: str | None = None,
        ending_before: str | None = None,
        t0: str | None = None,
        t1: str | None = None,
        timespan: float | None = None,
        total_pages: int | Literal["all"] = "all",
        direction: Literal["prev", "next"] = "next",
    ) -> AsyncPaginatedResponse[GetNetworkClientsApplicationUsageResponseItem]:
        """Return the application usage data for clients.

        [API documentation: getNetworkClientsApplicationUsage](https://developer.cisco.com/meraki/api-v1/#!get-network-clients-application-usage)

        Args:
            network_id: Network ID.
            clients: A list of client keys, MACs or IPs separated by comma.
            ssid_number: An SSID number to include. If not specified, events for all SSIDs will be
                returned.
            per_page: The number of entries per page returned. Acceptable range is 3 - 1000.
            starting_after: A token used by the server to indicate the start of the page. Often this
                is a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            ending_before: A token used by the server to indicate the end of the page. Often this is
                a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            t0: The beginning of the timespan for the data. The maximum lookback period is 31 days
                from today.
            t1: The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
            timespan: The timespan for which the information will be fetched. If specifying
                timespan, do not specify parameters t0 and t1. The value must be in
                seconds and be less than or equal to 31 days. The default is 1 day.
            total_pages: use with per_page to get total results up to total_pages * per_page; -1 or
                "all" for all pages.
            direction: direction to paginate, either "next" (default) or "prev" page.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "clientId": "k74272e",
                "clientIp": "1.2.3.4",
                "clientMac": "00:11:22:33:44:55",
                "applicationUsage": [
                  {
                    "application": "Meraki HTTPS",
                    "received": 61,
                    "sent": 138
                  }
                ]
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/clients/applicationUsage"

        params: dict[str, Any] = {}
        if clients is not None:
            params["clients"] = clients
        if ssid_number is not None:
            params["ssidNumber"] = ssid_number
        if per_page is not None:
            params["perPage"] = per_page
        if starting_after is not None:
            params["startingAfter"] = starting_after
        if ending_before is not None:
            params["endingBefore"] = ending_before
        if t0 is not None:
            params["t0"] = t0
        if t1 is not None:
            params["t1"] = t1
        if timespan is not None:
            params["timespan"] = timespan

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkClientsApplicationUsage",
            path=path,
            params=params,
            total_pages=total_pages,
            direction=direction,
            item_schema=GetNetworkClientsApplicationUsageResponseItem,
        )

    def get_network_clients_bandwidth_usage_history(
        self,
        network_id: str,
        *,
        t0: str | None = None,
        t1: str | None = None,
        timespan: float | None = None,
        per_page: int | None = None,
        starting_after: str | None = None,
        ending_before: str | None = None,
        total_pages: int | Literal["all"] = "all",
        direction: Literal["prev", "next"] = "next",
    ) -> AsyncPaginatedResponse[GetNetworkClientsBandwidthUsageHistoryResponseItem]:
        """Returns a timeseries of total traffic consumption rates for all clients on a network within a given timespan, in megabits per second.

        [API documentation: getNetworkClientsBandwidthUsageHistory](https://developer.cisco.com/meraki/api-v1/#!get-network-clients-bandwidth-usage-history)

        Args:
            network_id: Network ID.
            t0: The beginning of the timespan for the data. The maximum lookback period is 30 days
                from today.
            t1: The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
            timespan: The timespan for which the information will be fetched. If specifying
                timespan, do not specify parameters t0 and t1. The value must be in
                seconds and be less than or equal to 31 days. The default is 1 day.
            per_page: The number of entries per page returned. Acceptable range is 3 - 1000. Default
                is 1000.
            starting_after: A token used by the server to indicate the start of the page. Often this
                is a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            ending_before: A token used by the server to indicate the end of the page. Often this is
                a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            total_pages: use with per_page to get total results up to total_pages * per_page; -1 or
                "all" for all pages.
            direction: direction to paginate, either "next" (default) or "prev" page.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "ts": "2018-02-11T00:00:00.090210Z",
                "total": 345.0,
                "upstream": 200.0,
                "downstream": 145.0
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/clients/bandwidthUsageHistory"

        params: dict[str, Any] = {}
        if t0 is not None:
            params["t0"] = t0
        if t1 is not None:
            params["t1"] = t1
        if timespan is not None:
            params["timespan"] = timespan
        if per_page is not None:
            params["perPage"] = per_page
        if starting_after is not None:
            params["startingAfter"] = starting_after
        if ending_before is not None:
            params["endingBefore"] = ending_before

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkClientsBandwidthUsageHistory",
            path=path,
            params=params,
            total_pages=total_pages,
            direction=direction,
            item_schema=GetNetworkClientsBandwidthUsageHistoryResponseItem,
        )

    async def get_network_clients_overview(
        self,
        network_id: str,
        *,
        t0: str | None = None,
        t1: str | None = None,
        timespan: float | None = None,
        resolution: int | None = None,
    ) -> GetNetworkClientsOverviewResponse:
        """Return overview statistics for network clients.

        [API documentation: getNetworkClientsOverview](https://developer.cisco.com/meraki/api-v1/#!get-network-clients-overview)

        Args:
            network_id: Network ID.
            t0: The beginning of the timespan for the data. The maximum lookback period is 31 days
                from today.
            t1: The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
            timespan: The timespan for which the information will be fetched. If specifying
                timespan, do not specify parameters t0 and t1. The value must be in
                seconds and be less than or equal to 31 days. The default is 1 day.
            resolution: The time resolution in seconds for returned data. The valid resolutions are:
                7200, 86400, 604800, 2592000. The default is 604800.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "counts": {
                "total": 100,
                "withHeavyUsage": 2
              },
              "usages": {
                "average": 2048,
                "withHeavyUsageAverage": 5345
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/clients/overview"

        params: dict[str, Any] = {}
        if t0 is not None:
            params["t0"] = t0
        if t1 is not None:
            params["t1"] = t1
        if timespan is not None:
            params["timespan"] = timespan
        if resolution is not None:
            params["resolution"] = resolution

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkClientsOverview",
            path=path,
            params=params,
            response_schema=GetNetworkClientsOverviewResponse,
        )

    async def provision_network_clients(
        self,
        *,
        network_id: str,
        clients: list[ProvisionNetworkClientsClientsItem],
        device_policy: ProvisionNetworkClientsDevicePolicy,
        group_policy_id: str | None = None,
        policies_by_security_appliance: ProvisionNetworkClientsPoliciesBySecurityAppliance
        | None = None,
        policies_by_ssid: ProvisionNetworkClientsPoliciesBySsid | None = None,
    ) -> ProvisionNetworkClientsResponse:
        """Provisions a client with a name and policy.

        [API documentation: provisionNetworkClients](https://developer.cisco.com/meraki/api-v1/#!provision-network-clients)

        Args:
            network_id: Network ID.
            clients: The array of clients to provision.
            device_policy: The policy to apply to the specified client. Can be 'Group policy',
                'Allowed', 'Blocked', 'Per connection' or 'Normal'. Required.
            group_policy_id: The ID of the desired group policy to apply to the client. Required if
                'devicePolicy' is set to "Group policy". Otherwise this is ignored.
            policies_by_security_appliance: An object, describing what the policy-connection
                association is for the security appliance. (Only relevant if the
                security appliance is actually within the network).
            policies_by_ssid: An object, describing the policy-connection associations for each
                active SSID within the network. Keys should be the number of enabled
                SSIDs, mapping to an object describing the client's policy.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "clients": [
                {
                  "mac": "00:11:22:33:44:55",
                  "clientId": "k74272e",
                  "name": "Miles's phone",
                  "message": "Blocked message for client"
                }
              ],
              "devicePolicy": "Group policy",
              "groupPolicyId": "101"
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/clients/provision"

        payload: dict[str, Any] = {}
        if clients is not None:
            payload["clients"] = [
                item.model_dump(by_alias=True, exclude_none=True) for item in clients
            ]
        if device_policy is not None:
            payload["devicePolicy"] = device_policy
        if group_policy_id is not None:
            payload["groupPolicyId"] = group_policy_id
        if policies_by_security_appliance is not None:
            payload["policiesBySecurityAppliance"] = policies_by_security_appliance.model_dump(
                by_alias=True, exclude_none=True
            )
        if policies_by_ssid is not None:
            payload["policiesBySsid"] = policies_by_ssid.model_dump(
                by_alias=True, exclude_none=True
            )

        return await self._session.post(
            scope="networks",
            operation_id="provisionNetworkClients",
            path=path,
            json=payload,
            response_schema=ProvisionNetworkClientsResponse,
        )

    def get_network_clients_usage_histories(
        self,
        *,
        network_id: str,
        clients: str,
        ssid_number: GetNetworkClientsUsageHistoriesSsidNumber | None = None,
        per_page: int | None = None,
        starting_after: str | None = None,
        ending_before: str | None = None,
        t0: str | None = None,
        t1: str | None = None,
        timespan: float | None = None,
        total_pages: int | Literal["all"] = "all",
        direction: Literal["prev", "next"] = "next",
    ) -> AsyncPaginatedResponse[GetNetworkClientsUsageHistoriesResponseItem]:
        """Return the usage histories for clients.

        [API documentation: getNetworkClientsUsageHistories](https://developer.cisco.com/meraki/api-v1/#!get-network-clients-usage-histories)

        Args:
            network_id: Network ID.
            clients: A list of client keys, MACs or IPs separated by comma.
            ssid_number: An SSID number to include. If not specified, events for all SSIDs will be
                returned.
            per_page: The number of entries per page returned. Acceptable range is 3 - 1000.
            starting_after: A token used by the server to indicate the start of the page. Often this
                is a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            ending_before: A token used by the server to indicate the end of the page. Often this is
                a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            t0: The beginning of the timespan for the data. The maximum lookback period is 31 days
                from today.
            t1: The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
            timespan: The timespan for which the information will be fetched. If specifying
                timespan, do not specify parameters t0 and t1. The value must be in
                seconds and be less than or equal to 31 days. The default is 1 day.
            total_pages: use with per_page to get total results up to total_pages * per_page; -1 or
                "all" for all pages.
            direction: direction to paginate, either "next" (default) or "prev" page.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "clientId": "k74272e",
                "clientIp": "1.2.3.4",
                "clientMac": "00:11:22:33:44:55",
                "usageHistory": [
                  {
                    "received": 61.0,
                    "sent": 138.0,
                    "ts": "2018-02-11T00:00:00.090210Z"
                  }
                ]
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/clients/usageHistories"

        params: dict[str, Any] = {}
        if clients is not None:
            params["clients"] = clients
        if ssid_number is not None:
            params["ssidNumber"] = ssid_number
        if per_page is not None:
            params["perPage"] = per_page
        if starting_after is not None:
            params["startingAfter"] = starting_after
        if ending_before is not None:
            params["endingBefore"] = ending_before
        if t0 is not None:
            params["t0"] = t0
        if t1 is not None:
            params["t1"] = t1
        if timespan is not None:
            params["timespan"] = timespan

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkClientsUsageHistories",
            path=path,
            params=params,
            total_pages=total_pages,
            direction=direction,
            item_schema=GetNetworkClientsUsageHistoriesResponseItem,
        )

    async def get_network_client(
        self, *, network_id: str, client_id: str
    ) -> GetNetworkClientResponse:
        """Return the client associated with the given identifier.

        [API documentation: getNetworkClient](https://developer.cisco.com/meraki/api-v1/#!get-network-client)

        Args:
            network_id: Network ID.
            client_id: Client ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "id": "k74272e",
              "mac": "22:33:44:55:66:77",
              "ip": "1.2.3.4",
              "ip6": "2001:db8:3c4d:15::1",
              "ip6Local": "fe80:0:0:0:1430:aac1:6826:75ab",
              "description": "Miles's phone",
              "firstSeen": 1518365681,
              "lastSeen": 1526087474,
              "manufacturer": "Apple",
              "os": "iOS",
              "user": "milesmeraki",
              "vlan": "100",
              "namedVlan": "100",
              "ssid": "My SSID",
              "switchport": "My switch port",
              "wirelessCapabilities": "802.11b - 2.4 GHz",
              "smInstalled": true,
              "recentDeviceMac": "22:33:44:55:66:77",
              "recentDeviceName": "00:11:22:33:44:55",
              "recentDeviceSerial": "Q234-ABCD-5678",
              "recentDeviceConnection": "Wired",
              "clientVpnConnections": [
                {
                  "remoteIp": "1.2.3.4",
                  "connectedAt": 1522613355,
                  "disconnectedAt": 1522613360
                }
              ],
              "lldp": [
                [
                  "System name",
                  "Some system name"
                ],
                [
                  "System description",
                  "Some system description"
                ],
                [
                  "Port ID",
                  "1"
                ],
                [
                  "Chassis ID",
                  "00:18:0a:00:00:00"
                ],
                [
                  "Port description",
                  "eth0"
                ],
                [
                  "System capabilities",
                  "Two-port MAC Relay"
                ]
              ],
              "cdp": [
                [
                  "System name",
                  "Some system name"
                ],
                [
                  "System description",
                  "Some system description"
                ],
                [
                  "Port ID",
                  "1"
                ],
                [
                  "Chassis ID",
                  "00:18:0a:00:00:00"
                ],
                [
                  "Port description",
                  "eth0"
                ],
                [
                  "System capabilities",
                  "Two-port MAC Relay"
                ]
              ],
              "status": "Online",
              "notes": "My client note",
              "deviceTypePrediction": "iPhone SE, iOS9.3.5"
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        client_id = urllib.parse.quote(str(client_id), safe="")
        path = f"/networks/{network_id}/clients/{client_id}"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkClient",
            path=path,
            response_schema=GetNetworkClientResponse,
        )

    async def get_network_client_policy(
        self, *, network_id: str, client_id: str
    ) -> GetNetworkClientPolicyResponse:
        """Return the policy assigned to a client on the network.

        [API documentation: getNetworkClientPolicy](https://developer.cisco.com/meraki/api-v1/#!get-network-client-policy)

        Args:
            network_id: Network ID.
            client_id: Client ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "mac": "00:11:22:33:44:55",
              "devicePolicy": "Different policies by SSID",
              "groupPolicyId": "101",
              "policiesBySsid": [
                {
                  "ssidNumber": 2,
                  "devicePolicy": "Group policy",
                  "groupPolicyId": "101"
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        client_id = urllib.parse.quote(str(client_id), safe="")
        path = f"/networks/{network_id}/clients/{client_id}/policy"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkClientPolicy",
            path=path,
            response_schema=GetNetworkClientPolicyResponse,
        )

    async def update_network_client_policy(
        self,
        *,
        network_id: str,
        client_id: str,
        device_policy: str,
        group_policy_id: str | None = None,
    ) -> UpdateNetworkClientPolicyResponse:
        """Update the policy assigned to a client on the network.

        [API documentation: updateNetworkClientPolicy](https://developer.cisco.com/meraki/api-v1/#!update-network-client-policy)

        Args:
            network_id: Network ID.
            client_id: Client ID.
            device_policy: The policy to assign. Can be 'Whitelisted', 'Blocked', 'Normal' or 'Group
                policy'. Required.
            group_policy_id: [Optional] If 'devicePolicy' is set to 'Group policy' this param is
                used to specify the group policy ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "mac": "00:11:22:33:44:55",
              "devicePolicy": "Different policies by SSID",
              "groupPolicyId": "101",
              "policiesBySsid": [
                {
                  "ssidNumber": 2,
                  "devicePolicy": "Group policy",
                  "groupPolicyId": "101"
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        client_id = urllib.parse.quote(str(client_id), safe="")
        path = f"/networks/{network_id}/clients/{client_id}/policy"

        payload: dict[str, Any] = {}
        if device_policy is not None:
            payload["devicePolicy"] = device_policy
        if group_policy_id is not None:
            payload["groupPolicyId"] = group_policy_id

        return await self._session.put(
            scope="networks",
            operation_id="updateNetworkClientPolicy",
            path=path,
            json=payload,
            response_schema=UpdateNetworkClientPolicyResponse,
        )

    async def get_network_client_splash_authorization_status(
        self, *, network_id: str, client_id: str
    ) -> DictResponse:
        """Return the splash authorization for a client, for each SSID they've associated with through splash.

        [API documentation: getNetworkClientSplashAuthorizationStatus](https://developer.cisco.com/meraki/api-v1/#!get-network-client-splash-authorization-status)

        Args:
            network_id: Network ID.
            client_id: Client ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "ssids": {
                "0": {
                  "isAuthorized": true,
                  "authorizedAt": "2018-02-11T00:00:00Z",
                  "expiresAt": "2018-05-12T00:00:00Z"
                }
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        client_id = urllib.parse.quote(str(client_id), safe="")
        path = f"/networks/{network_id}/clients/{client_id}/splashAuthorizationStatus"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkClientSplashAuthorizationStatus",
            path=path,
            response_schema=DictResponse,
        )

    async def update_network_client_splash_authorization_status(
        self,
        *,
        network_id: str,
        client_id: str,
        ssids: UpdateNetworkClientSplashAuthorizationStatusSsids,
    ) -> DictResponse:
        """Update a client's splash authorization.

        [API documentation: updateNetworkClientSplashAuthorizationStatus](https://developer.cisco.com/meraki/api-v1/#!update-network-client-splash-authorization-status)

        Args:
            network_id: Network ID.
            client_id: Client ID.
            ssids: The target SSIDs. Each SSID must be enabled and must have Click-through splash
                enabled. For each SSID where isAuthorized is true, the expiration time
                will automatically be set according to the SSID's splash frequency. Not
                all networks support configuring all SSIDs.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "ssids": {
                "0": {
                  "isAuthorized": true,
                  "authorizedAt": "2017-07-19 16:24:13 UTC",
                  "expiresAt": "2017-07-20 16:24:13 UTC"
                },
                "2": {
                  "isAuthorized": false
                }
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        client_id = urllib.parse.quote(str(client_id), safe="")
        path = f"/networks/{network_id}/clients/{client_id}/splashAuthorizationStatus"

        payload: dict[str, Any] = {}
        if ssids is not None:
            payload["ssids"] = ssids.model_dump(by_alias=True, exclude_none=True)

        return await self._session.put(
            scope="networks",
            operation_id="updateNetworkClientSplashAuthorizationStatus",
            path=path,
            json=payload,
            response_schema=DictResponse,
        )

    def get_network_client_traffic_history(
        self,
        *,
        network_id: str,
        client_id: str,
        per_page: int | None = None,
        starting_after: str | None = None,
        ending_before: str | None = None,
        total_pages: int | Literal["all"] = "all",
        direction: Literal["prev", "next"] = "next",
    ) -> AsyncPaginatedResponse[GetNetworkClientTrafficHistoryResponseItem]:
        """Return the client's network traffic data over time.

        [API documentation: getNetworkClientTrafficHistory](https://developer.cisco.com/meraki/api-v1/#!get-network-client-traffic-history)

        Args:
            network_id: Network ID.
            client_id: Client ID.
            per_page: The number of entries per page returned. Acceptable range is 3 - 1000.
            starting_after: A token used by the server to indicate the start of the page. Often this
                is a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            ending_before: A token used by the server to indicate the end of the page. Often this is
                a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            total_pages: use with per_page to get total results up to total_pages * per_page; -1 or
                "all" for all pages.
            direction: direction to paginate, either "next" (default) or "prev" page.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "ts": "2018-02-11T00:00:00.090210Z",
                "application": "Google",
                "destination": "www.google.com",
                "protocol": "TCP",
                "port": 443,
                "recv": 61.0,
                "sent": 138.0,
                "numFlows": 5,
                "activeSeconds": 240
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        client_id = urllib.parse.quote(str(client_id), safe="")
        path = f"/networks/{network_id}/clients/{client_id}/trafficHistory"

        params: dict[str, Any] = {}
        if per_page is not None:
            params["perPage"] = per_page
        if starting_after is not None:
            params["startingAfter"] = starting_after
        if ending_before is not None:
            params["endingBefore"] = ending_before

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkClientTrafficHistory",
            path=path,
            params=params,
            total_pages=total_pages,
            direction=direction,
            item_schema=GetNetworkClientTrafficHistoryResponseItem,
        )

    def get_network_client_usage_history(
        self, *, network_id: str, client_id: str
    ) -> AsyncPaginatedResponse[GetNetworkClientUsageHistoryResponseItem]:
        """Return the client's daily usage history.

        [API documentation: getNetworkClientUsageHistory](https://developer.cisco.com/meraki/api-v1/#!get-network-client-usage-history)

        Args:
            network_id: Network ID.
            client_id: Client ID.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "received": 61.0,
                "sent": 138.0,
                "ts": "2018-02-11T00:00:00.090210Z"
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        client_id = urllib.parse.quote(str(client_id), safe="")
        path = f"/networks/{network_id}/clients/{client_id}/usageHistory"

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkClientUsageHistory",
            path=path,
            item_schema=GetNetworkClientUsageHistoryResponseItem,
        )

    def get_network_devices(
        self, network_id: str
    ) -> AsyncPaginatedResponse[GetNetworkDevicesResponseItem]:
        """List the devices in a network.

        [API documentation: getNetworkDevices](https://developer.cisco.com/meraki/api-v1/#!get-network-devices)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "name": "My AP",
                "lat": 37.4180951010362,
                "lng": -122.098531723022,
                "address": "1600 Pennsylvania Ave",
                "notes": "My AP's note",
                "tags": [
                  " recently-added "
                ],
                "networkId": "N_24329156",
                "serial": "Q234-ABCD-5678",
                "model": "MR34",
                "mac": "00:11:22:33:44:55",
                "lanIp": "1.2.3.4",
                "firmware": "wireless-25-14",
                "floorPlanId": "g_2176982374",
                "details": [
                  {
                    "name": "Catalyst serial",
                    "value": "123ABC"
                  }
                ],
                "beaconIdParams": {
                  "uuid": "00000000-0000-0000-0000-000000000000",
                  "major": 5,
                  "minor": 3
                }
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/devices"

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkDevices",
            path=path,
            item_schema=GetNetworkDevicesResponseItem,
        )

    async def claim_network_devices(
        self,
        *,
        network_id: str,
        serials: list[str],
        add_atomically: bool | None = None,
        details_by_device: list[ClaimNetworkDevicesDetailsByDeviceItem] | None = None,
    ) -> ClaimNetworkDevicesResponse:
        """Claim devices into a network. (Note: for recently claimed devices, it may take a few minutes for API requests against that device to succeed).

        [API documentation: claimNetworkDevices](https://developer.cisco.com/meraki/api-v1/#!claim-network-devices)

        Args:
            network_id: Network ID.
            add_atomically: Whether to claim devices atomically. If true, all devices will be
                claimed or none will be claimed. Default is true.
            serials: A list of serials of devices to claim.
            details_by_device: Optional details for claimed devices (currently only used for
                Catalyst devices).

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "serials": [
                "Q234-ABCD-0001",
                "Q234-ABCD-0002",
                "Q234-ABCD-0003"
              ],
              "errors": [
                {
                  "serial": "Q234-ABCD-5678",
                  "errors": [
                    "Device already claimed"
                  ]
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/devices/claim"

        params: dict[str, Any] = {}
        if add_atomically is not None:
            params["addAtomically"] = add_atomically

        payload: dict[str, Any] = {}
        if serials is not None:
            payload["serials"] = serials
        if details_by_device is not None:
            payload["detailsByDevice"] = [
                item.model_dump(by_alias=True, exclude_none=True) for item in details_by_device
            ]

        return await self._session.post(
            scope="networks",
            operation_id="claimNetworkDevices",
            path=path,
            json=payload,
            response_schema=ClaimNetworkDevicesResponse,
        )

    async def vmx_network_devices_claim(
        self, *, network_id: str, size: VmxNetworkDevicesClaimSize
    ) -> VmxNetworkDevicesClaimResponse:
        """Claim a vMX into a network.

        [API documentation: vmxNetworkDevicesClaim](https://developer.cisco.com/meraki/api-v1/#!vmx-network-devices-claim)

        Args:
            network_id: Network ID.
            size: The size of the vMX you claim. It can be one of: small, medium, large, xlarge,
                100.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "name": "My AP",
              "lat": 37.4180951010362,
              "lng": -122.098531723022,
              "address": "1600 Pennsylvania Ave",
              "notes": "My AP's note",
              "tags": [
                "recently-added"
              ],
              "networkId": "N_24329156",
              "serial": "Q234-ABCD-5678",
              "model": "MR34",
              "imei": "123456789000000",
              "mac": "00:11:22:33:44:55",
              "lanIp": "1.2.3.4",
              "firmware": "wireless-25-14",
              "productType": "wireless",
              "details": [
                {
                  "name": "Catalyst serial",
                  "value": "123ABC"
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/devices/claim/vmx"

        payload: dict[str, Any] = {}
        if size is not None:
            payload["size"] = size

        return await self._session.post(
            scope="networks",
            operation_id="vmxNetworkDevicesClaim",
            path=path,
            json=payload,
            response_schema=VmxNetworkDevicesClaimResponse,
        )

    async def remove_network_devices(self, *, network_id: str, serial: str) -> None:
        """Remove a single device.

        [API documentation: removeNetworkDevices](https://developer.cisco.com/meraki/api-v1/#!remove-network-devices)

        Args:
            network_id: Network ID.
            serial: The serial of a device.

        Returns:
            Successful operation.

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/devices/remove"

        payload: dict[str, Any] = {}
        if serial is not None:
            payload["serial"] = serial

        return await self._session.post(
            scope="networks", operation_id="removeNetworkDevices", path=path, json=payload
        )

    def get_network_events(
        self,
        network_id: str,
        *,
        product_type: GetNetworkEventsProductType | None = None,
        included_event_types: list[str] | None = None,
        excluded_event_types: list[str] | None = None,
        device_mac: str | None = None,
        device_serial: str | None = None,
        device_name: str | None = None,
        client_ip: str | None = None,
        client_mac: str | None = None,
        client_name: str | None = None,
        sm_device_mac: str | None = None,
        sm_device_name: str | None = None,
        event_details: str | None = None,
        event_severity: str | None = None,
        is_catalyst: bool | None = None,
        per_page: int | None = None,
        starting_after: str | None = None,
        ending_before: str | None = None,
        total_pages: int | Literal["all"] = "all",
        direction: Literal["prev", "next"] = "prev",
        event_log_end_time: str | None = None,
    ) -> AsyncPaginatedResponse[GetNetworkEventsResponseEventsItem]:
        """List the events for the network.

        [API documentation: getNetworkEvents](https://developer.cisco.com/meraki/api-v1/#!get-network-events)

        Args:
            network_id: Network ID.
            product_type: The product type to fetch events for. This parameter is required for
                networks with multiple device types. Valid types are wireless,
                appliance, switch, systemsManager, camera, cellularGateway,
                wirelessController, campusGateway, and secureConnect.
            included_event_types: A list of event types. The returned events will be filtered to
                only include events with these types.
            excluded_event_types: A list of event types. The returned events will be filtered to
                exclude events with these types.
            device_mac: The MAC address of the Meraki device which the list of events will be
                filtered with.
            device_serial: The serial of the Meraki device which the list of events will be filtered
                with.
            device_name: The name of the Meraki device which the list of events will be filtered
                with.
            client_ip: The IP of the client which the list of events will be filtered with. Only
                supported for track-by-IP networks.
            client_mac: The MAC address of the client which the list of events will be filtered
                with. Only supported for track-by-MAC networks.
            client_name: The name, or partial name, of the client which the list of events will be
                filtered with.
            sm_device_mac: The MAC address of the Systems Manager device which the list of events
                will be filtered with.
            sm_device_name: The name of the Systems Manager device which the list of events will be
                filtered with.
            event_details: The details of the event(Catalyst device only) which the list of events
                will be filtered with.
            event_severity: The severity of the event(Catalyst device only) which the list of events
                will be filtered with.
            is_catalyst: Boolean indicating that whether it is a Catalyst device. For Catalyst
                device, eventDetails and eventSeverity can be used to filter events.
            per_page: The number of entries per page returned. Acceptable range is 3 - 1000. Default
                is 10.
            starting_after: A token used by the server to indicate the start of the page. Often this
                is a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            ending_before: A token used by the server to indicate the end of the page. Often this is
                a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            total_pages: use with per_page to get total results up to total_pages * per_page; -1 or
                "all" for all pages.
            direction: direction to paginate, either "next" or "prev" (default) page.
            event_log_end_time: ISO8601 Zulu/UTC time, to use in conjunction with starting_after, to
                retrieve events within a time window.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            {
              "message": "Some error",
              "pageStartAt": "2018-02-11T00:00:00.090210Z",
              "pageEndAt": "2018-02-11T00:00:00.090210Z",
              "events": [
                {
                  "occurredAt": "2018-02-11T00:00:00.090210Z",
                  "networkId": "N_24329156",
                  "type": "association",
                  "description": "802.11 association",
                  "category": "80211",
                  "clientId": "k74272e",
                  "clientDescription": "Miles's phone",
                  "clientMac": "22:33:44:55:66:77",
                  "deviceSerial": "Q234-ABCD-5678",
                  "deviceName": "My AP",
                  "ssidNumber": 1,
                  "eventData": {
                    "radio": "1",
                    "vap": "1",
                    "client_mac": "22:33:44:55:66:77",
                    "client_ip": "1.2.3.4",
                    "channel": "36",
                    "rssi": "12",
                    "aid": "2104009183"
                  }
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/events"

        params: dict[str, Any] = {}
        if product_type is not None:
            params["productType"] = product_type
        if included_event_types is not None:
            params["includedEventTypes[]"] = included_event_types
        if excluded_event_types is not None:
            params["excludedEventTypes[]"] = excluded_event_types
        if device_mac is not None:
            params["deviceMac"] = device_mac
        if device_serial is not None:
            params["deviceSerial"] = device_serial
        if device_name is not None:
            params["deviceName"] = device_name
        if client_ip is not None:
            params["clientIp"] = client_ip
        if client_mac is not None:
            params["clientMac"] = client_mac
        if client_name is not None:
            params["clientName"] = client_name
        if sm_device_mac is not None:
            params["smDeviceMac"] = sm_device_mac
        if sm_device_name is not None:
            params["smDeviceName"] = sm_device_name
        if event_details is not None:
            params["eventDetails"] = event_details
        if event_severity is not None:
            params["eventSeverity"] = event_severity
        if is_catalyst is not None:
            params["isCatalyst"] = is_catalyst
        if per_page is not None:
            params["perPage"] = per_page
        if starting_after is not None:
            params["startingAfter"] = starting_after
        if ending_before is not None:
            params["endingBefore"] = ending_before

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkEvents",
            path=path,
            params=params,
            total_pages=total_pages,
            direction=direction,
            event_log_end_time=event_log_end_time,
            item_schema=GetNetworkEventsResponseEventsItem,
        )

    def get_network_events_event_types(
        self, network_id: str
    ) -> AsyncPaginatedResponse[GetNetworkEventsEventTypesResponseItem]:
        """List the event type to human-readable description.

        [API documentation: getNetworkEventsEventTypes](https://developer.cisco.com/meraki/api-v1/#!get-network-events-event-types)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "category": "802.11",
                "type": "association",
                "description": "802.11 association"
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/events/eventTypes"

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkEventsEventTypes",
            path=path,
            item_schema=GetNetworkEventsEventTypesResponseItem,
        )

    async def get_network_firmware_upgrades(
        self, network_id: str
    ) -> GetNetworkFirmwareUpgradesResponse:
        """Get firmware upgrade information for a network.

        [API documentation: getNetworkFirmwareUpgrades](https://developer.cisco.com/meraki/api-v1/#!get-network-firmware-upgrades)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "upgradeWindow": {
                "dayOfWeek": "sun",
                "hourOfDay": "4:00"
              },
              "timezone": "America/Los_Angeles",
              "products": {
                "wireless": {
                  "currentVersion": {
                    "id": "4321",
                    "firmware": "camera-11-2-1",
                    "shortName": "MV 11.2.1",
                    "releaseType": "stable",
                    "releaseDate": "2020-03-17T17:22:52Z"
                  },
                  "lastUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "fromVersion": {
                      "id": "1234",
                      "firmware": "camera-10-8-1",
                      "shortName": "MV 10.8.1",
                      "releaseType": "stable",
                      "releaseDate": "2021-03-17T17:22:52Z"
                    },
                    "toVersion": {
                      "id": "4321",
                      "firmware": "camera-11-2-1",
                      "shortName": "MV 11.2.1",
                      "releaseType": "stable",
                      "releaseDate": "2019-03-17T17:22:52Z"
                    }
                  },
                  "nextUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "toVersion": {
                      "id": "2134",
                      "firmware": "camera-15-5-2",
                      "shortName": "MV 25.5.2",
                      "releaseType": "stable",
                      "releaseDate": "2021-05-28T17:22:52Z"
                    }
                  },
                  "isUpgradeAvailable": false,
                  "availableVersions": [
                    {
                      "id": "3421",
                      "firmware": "camera-16-x-y",
                      "shortName": "MV 16.x.y",
                      "releaseType": "beta",
                      "releaseDate": "2020-11-28T17:22:52Z"
                    }
                  ],
                  "participateInNextBetaRelease": false
                },
                "appliance": {
                  "currentVersion": {
                    "id": "4321",
                    "firmware": "camera-11-2-1",
                    "shortName": "MV 11.2.1",
                    "releaseType": "stable",
                    "releaseDate": "2020-03-17T17:22:52Z"
                  },
                  "lastUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "fromVersion": {
                      "id": "1234",
                      "firmware": "camera-10-8-1",
                      "shortName": "MV 10.8.1",
                      "releaseType": "stable",
                      "releaseDate": "2021-03-17T17:22:52Z"
                    },
                    "toVersion": {
                      "id": "4321",
                      "firmware": "camera-11-2-1",
                      "shortName": "MV 11.2.1",
                      "releaseType": "stable",
                      "releaseDate": "2019-03-17T17:22:52Z"
                    }
                  },
                  "nextUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "toVersion": {
                      "id": "2134",
                      "firmware": "camera-15-5-2",
                      "shortName": "MV 25.5.2",
                      "releaseType": "stable",
                      "releaseDate": "2021-05-28T17:22:52Z"
                    }
                  },
                  "isUpgradeAvailable": false,
                  "availableVersions": [
                    {
                      "id": "3421",
                      "firmware": "camera-16-x-y",
                      "shortName": "MV 16.x.y",
                      "releaseType": "beta",
                      "releaseDate": "2020-11-28T17:22:52Z"
                    }
                  ],
                  "participateInNextBetaRelease": false
                },
                "switch": {
                  "currentVersion": {
                    "id": "4321",
                    "firmware": "camera-11-2-1",
                    "shortName": "MV 11.2.1",
                    "releaseType": "stable",
                    "releaseDate": "2020-03-17T17:22:52Z"
                  },
                  "lastUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "fromVersion": {
                      "id": "1234",
                      "firmware": "camera-10-8-1",
                      "shortName": "MV 10.8.1",
                      "releaseType": "stable",
                      "releaseDate": "2021-03-17T17:22:52Z"
                    },
                    "toVersion": {
                      "id": "4321",
                      "firmware": "camera-11-2-1",
                      "shortName": "MV 11.2.1",
                      "releaseType": "stable",
                      "releaseDate": "2019-03-17T17:22:52Z"
                    }
                  },
                  "nextUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "toVersion": {
                      "id": "2134",
                      "firmware": "camera-15-5-2",
                      "shortName": "MV 25.5.2",
                      "releaseType": "stable",
                      "releaseDate": "2021-05-28T17:22:52Z"
                    }
                  },
                  "isUpgradeAvailable": false,
                  "availableVersions": [
                    {
                      "id": "3421",
                      "firmware": "camera-16-x-y",
                      "shortName": "MV 16.x.y",
                      "releaseType": "beta",
                      "releaseDate": "2020-11-28T17:22:52Z"
                    }
                  ],
                  "participateInNextBetaRelease": false
                },
                "camera": {
                  "currentVersion": {
                    "id": "4321",
                    "firmware": "camera-11-2-1",
                    "shortName": "MV 11.2.1",
                    "releaseType": "stable",
                    "releaseDate": "2020-03-17T17:22:52Z"
                  },
                  "lastUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "fromVersion": {
                      "id": "1234",
                      "firmware": "camera-10-8-1",
                      "shortName": "MV 10.8.1",
                      "releaseType": "stable",
                      "releaseDate": "2021-03-17T17:22:52Z"
                    },
                    "toVersion": {
                      "id": "4321",
                      "firmware": "camera-11-2-1",
                      "shortName": "MV 11.2.1",
                      "releaseType": "stable",
                      "releaseDate": "2019-03-17T17:22:52Z"
                    }
                  },
                  "nextUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "toVersion": {
                      "id": "2134",
                      "firmware": "camera-15-5-2",
                      "shortName": "MV 25.5.2",
                      "releaseType": "stable",
                      "releaseDate": "2021-05-28T17:22:52Z"
                    }
                  },
                  "isUpgradeAvailable": false,
                  "availableVersions": [
                    {
                      "id": "3421",
                      "firmware": "camera-16-x-y",
                      "shortName": "MV 16.x.y",
                      "releaseType": "beta",
                      "releaseDate": "2020-11-28T17:22:52Z"
                    }
                  ],
                  "participateInNextBetaRelease": false
                },
                "cellularGateway": {
                  "currentVersion": {
                    "id": "4321",
                    "firmware": "camera-11-2-1",
                    "shortName": "MV 11.2.1",
                    "releaseType": "stable",
                    "releaseDate": "2020-03-17T17:22:52Z"
                  },
                  "lastUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "fromVersion": {
                      "id": "1234",
                      "firmware": "camera-10-8-1",
                      "shortName": "MV 10.8.1",
                      "releaseType": "stable",
                      "releaseDate": "2021-03-17T17:22:52Z"
                    },
                    "toVersion": {
                      "id": "4321",
                      "firmware": "camera-11-2-1",
                      "shortName": "MV 11.2.1",
                      "releaseType": "stable",
                      "releaseDate": "2019-03-17T17:22:52Z"
                    }
                  },
                  "nextUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "toVersion": {
                      "id": "2134",
                      "firmware": "camera-15-5-2",
                      "shortName": "MV 25.5.2",
                      "releaseType": "stable",
                      "releaseDate": "2021-05-28T17:22:52Z"
                    }
                  },
                  "isUpgradeAvailable": false,
                  "availableVersions": [
                    {
                      "id": "3421",
                      "firmware": "camera-16-x-y",
                      "shortName": "MV 16.x.y",
                      "releaseType": "beta",
                      "releaseDate": "2020-11-28T17:22:52Z"
                    }
                  ],
                  "participateInNextBetaRelease": false
                },
                "sensor": {
                  "currentVersion": {
                    "id": "4321",
                    "firmware": "camera-11-2-1",
                    "shortName": "MV 11.2.1",
                    "releaseType": "stable",
                    "releaseDate": "2020-03-17T17:22:52Z"
                  },
                  "lastUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "fromVersion": {
                      "id": "1234",
                      "firmware": "camera-10-8-1",
                      "shortName": "MV 10.8.1",
                      "releaseType": "stable",
                      "releaseDate": "2021-03-17T17:22:52Z"
                    },
                    "toVersion": {
                      "id": "4321",
                      "firmware": "camera-11-2-1",
                      "shortName": "MV 11.2.1",
                      "releaseType": "stable",
                      "releaseDate": "2019-03-17T17:22:52Z"
                    }
                  },
                  "nextUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "toVersion": {
                      "id": "2134",
                      "firmware": "camera-15-5-2",
                      "shortName": "MV 25.5.2",
                      "releaseType": "stable",
                      "releaseDate": "2021-05-28T17:22:52Z"
                    }
                  },
                  "isUpgradeAvailable": false,
                  "availableVersions": [
                    {
                      "id": "3421",
                      "firmware": "camera-16-x-y",
                      "shortName": "MV 16.x.y",
                      "releaseType": "beta",
                      "releaseDate": "2020-11-28T17:22:52Z"
                    }
                  ],
                  "participateInNextBetaRelease": false
                },
                "wirelessController": {
                  "currentVersion": {
                    "id": "4321",
                    "firmware": "camera-11-2-1",
                    "shortName": "MV 11.2.1",
                    "releaseType": "stable",
                    "releaseDate": "2020-03-17T17:22:52Z"
                  },
                  "lastUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "fromVersion": {
                      "id": "1234",
                      "firmware": "camera-10-8-1",
                      "shortName": "MV 10.8.1",
                      "releaseType": "stable",
                      "releaseDate": "2021-03-17T17:22:52Z"
                    },
                    "toVersion": {
                      "id": "4321",
                      "firmware": "camera-11-2-1",
                      "shortName": "MV 11.2.1",
                      "releaseType": "stable",
                      "releaseDate": "2019-03-17T17:22:52Z"
                    }
                  },
                  "nextUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "toVersion": {
                      "id": "2134",
                      "firmware": "camera-15-5-2",
                      "shortName": "MV 25.5.2",
                      "releaseType": "stable",
                      "releaseDate": "2021-05-28T17:22:52Z"
                    }
                  },
                  "isUpgradeAvailable": false,
                  "availableVersions": [
                    {
                      "id": "3421",
                      "firmware": "camera-16-x-y",
                      "shortName": "MV 16.x.y",
                      "releaseType": "beta",
                      "releaseDate": "2020-11-28T17:22:52Z"
                    }
                  ],
                  "participateInNextBetaRelease": false
                },
                "secureConnect": {
                  "currentVersion": {
                    "id": "4321",
                    "firmware": "camera-11-2-1",
                    "shortName": "MV 11.2.1",
                    "releaseType": "stable",
                    "releaseDate": "2020-03-17T17:22:52Z"
                  },
                  "lastUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "fromVersion": {
                      "id": "1234",
                      "firmware": "camera-10-8-1",
                      "shortName": "MV 10.8.1",
                      "releaseType": "stable",
                      "releaseDate": "2021-03-17T17:22:52Z"
                    },
                    "toVersion": {
                      "id": "4321",
                      "firmware": "camera-11-2-1",
                      "shortName": "MV 11.2.1",
                      "releaseType": "stable",
                      "releaseDate": "2019-03-17T17:22:52Z"
                    }
                  },
                  "nextUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "toVersion": {
                      "id": "2134",
                      "firmware": "camera-15-5-2",
                      "shortName": "MV 25.5.2",
                      "releaseType": "stable",
                      "releaseDate": "2021-05-28T17:22:52Z"
                    }
                  },
                  "isUpgradeAvailable": false,
                  "availableVersions": [
                    {
                      "id": "3421",
                      "firmware": "camera-16-x-y",
                      "shortName": "MV 16.x.y",
                      "releaseType": "beta",
                      "releaseDate": "2020-11-28T17:22:52Z"
                    }
                  ],
                  "participateInNextBetaRelease": false
                }
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/firmwareUpgrades"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkFirmwareUpgrades",
            path=path,
            response_schema=GetNetworkFirmwareUpgradesResponse,
        )

    async def update_network_firmware_upgrades(
        self,
        network_id: str,
        *,
        upgrade_window: UpdateNetworkFirmwareUpgradesUpgradeWindow | None = None,
        timezone: str | None = None,
        products: UpdateNetworkFirmwareUpgradesProducts | None = None,
    ) -> UpdateNetworkFirmwareUpgradesResponse:
        """Update firmware upgrade information for a network.

        [API documentation: updateNetworkFirmwareUpgrades](https://developer.cisco.com/meraki/api-v1/#!update-network-firmware-upgrades)

        Args:
            network_id: Network ID.
            upgrade_window: Upgrade window for devices in network.
            timezone: The timezone for the network.
            products: Contains information about the network to update.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "upgradeWindow": {
                "dayOfWeek": "sun",
                "hourOfDay": "4:00"
              },
              "timezone": "America/Los_Angeles",
              "products": {
                "wireless": {
                  "currentVersion": {
                    "id": "4321",
                    "firmware": "camera-11-2-1",
                    "shortName": "MV 11.2.1",
                    "releaseType": "stable",
                    "releaseDate": "2020-03-17T17:22:52Z"
                  },
                  "lastUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "fromVersion": {
                      "id": "1234",
                      "firmware": "camera-10-8-1",
                      "shortName": "MV 10.8.1",
                      "releaseType": "stable",
                      "releaseDate": "2021-03-17T17:22:52Z"
                    },
                    "toVersion": {
                      "id": "4321",
                      "firmware": "camera-11-2-1",
                      "shortName": "MV 11.2.1",
                      "releaseType": "stable",
                      "releaseDate": "2019-03-17T17:22:52Z"
                    }
                  },
                  "nextUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "toVersion": {
                      "id": "2134",
                      "firmware": "camera-15-5-2",
                      "shortName": "MV 25.5.2",
                      "releaseType": "stable",
                      "releaseDate": "2021-05-28T17:22:52Z"
                    }
                  },
                  "isUpgradeAvailable": false,
                  "availableVersions": [
                    {
                      "id": "3421",
                      "firmware": "camera-16-x-y",
                      "shortName": "MV 16.x.y",
                      "releaseType": "beta",
                      "releaseDate": "2020-11-28T17:22:52Z"
                    }
                  ],
                  "participateInNextBetaRelease": false
                },
                "appliance": {
                  "currentVersion": {
                    "id": "4321",
                    "firmware": "camera-11-2-1",
                    "shortName": "MV 11.2.1",
                    "releaseType": "stable",
                    "releaseDate": "2020-03-17T17:22:52Z"
                  },
                  "lastUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "fromVersion": {
                      "id": "1234",
                      "firmware": "camera-10-8-1",
                      "shortName": "MV 10.8.1",
                      "releaseType": "stable",
                      "releaseDate": "2021-03-17T17:22:52Z"
                    },
                    "toVersion": {
                      "id": "4321",
                      "firmware": "camera-11-2-1",
                      "shortName": "MV 11.2.1",
                      "releaseType": "stable",
                      "releaseDate": "2019-03-17T17:22:52Z"
                    }
                  },
                  "nextUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "toVersion": {
                      "id": "2134",
                      "firmware": "camera-15-5-2",
                      "shortName": "MV 25.5.2",
                      "releaseType": "stable",
                      "releaseDate": "2021-05-28T17:22:52Z"
                    }
                  },
                  "isUpgradeAvailable": false,
                  "availableVersions": [
                    {
                      "id": "3421",
                      "firmware": "camera-16-x-y",
                      "shortName": "MV 16.x.y",
                      "releaseType": "beta",
                      "releaseDate": "2020-11-28T17:22:52Z"
                    }
                  ],
                  "participateInNextBetaRelease": false
                },
                "switch": {
                  "currentVersion": {
                    "id": "4321",
                    "firmware": "camera-11-2-1",
                    "shortName": "MV 11.2.1",
                    "releaseType": "stable",
                    "releaseDate": "2020-03-17T17:22:52Z"
                  },
                  "lastUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "fromVersion": {
                      "id": "1234",
                      "firmware": "camera-10-8-1",
                      "shortName": "MV 10.8.1",
                      "releaseType": "stable",
                      "releaseDate": "2021-03-17T17:22:52Z"
                    },
                    "toVersion": {
                      "id": "4321",
                      "firmware": "camera-11-2-1",
                      "shortName": "MV 11.2.1",
                      "releaseType": "stable",
                      "releaseDate": "2019-03-17T17:22:52Z"
                    }
                  },
                  "nextUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "toVersion": {
                      "id": "2134",
                      "firmware": "camera-15-5-2",
                      "shortName": "MV 25.5.2",
                      "releaseType": "stable",
                      "releaseDate": "2021-05-28T17:22:52Z"
                    }
                  },
                  "isUpgradeAvailable": false,
                  "availableVersions": [
                    {
                      "id": "3421",
                      "firmware": "camera-16-x-y",
                      "shortName": "MV 16.x.y",
                      "releaseType": "beta",
                      "releaseDate": "2020-11-28T17:22:52Z"
                    }
                  ],
                  "participateInNextBetaRelease": false
                },
                "camera": {
                  "currentVersion": {
                    "id": "4321",
                    "firmware": "camera-11-2-1",
                    "shortName": "MV 11.2.1",
                    "releaseType": "stable",
                    "releaseDate": "2020-03-17T17:22:52Z"
                  },
                  "lastUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "fromVersion": {
                      "id": "1234",
                      "firmware": "camera-10-8-1",
                      "shortName": "MV 10.8.1",
                      "releaseType": "stable",
                      "releaseDate": "2021-03-17T17:22:52Z"
                    },
                    "toVersion": {
                      "id": "4321",
                      "firmware": "camera-11-2-1",
                      "shortName": "MV 11.2.1",
                      "releaseType": "stable",
                      "releaseDate": "2019-03-17T17:22:52Z"
                    }
                  },
                  "nextUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "toVersion": {
                      "id": "2134",
                      "firmware": "camera-15-5-2",
                      "shortName": "MV 25.5.2",
                      "releaseType": "stable",
                      "releaseDate": "2021-05-28T17:22:52Z"
                    }
                  },
                  "isUpgradeAvailable": false,
                  "availableVersions": [
                    {
                      "id": "3421",
                      "firmware": "camera-16-x-y",
                      "shortName": "MV 16.x.y",
                      "releaseType": "beta",
                      "releaseDate": "2020-11-28T17:22:52Z"
                    }
                  ],
                  "participateInNextBetaRelease": false
                },
                "cellularGateway": {
                  "currentVersion": {
                    "id": "4321",
                    "firmware": "camera-11-2-1",
                    "shortName": "MV 11.2.1",
                    "releaseType": "stable",
                    "releaseDate": "2020-03-17T17:22:52Z"
                  },
                  "lastUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "fromVersion": {
                      "id": "1234",
                      "firmware": "camera-10-8-1",
                      "shortName": "MV 10.8.1",
                      "releaseType": "stable",
                      "releaseDate": "2021-03-17T17:22:52Z"
                    },
                    "toVersion": {
                      "id": "4321",
                      "firmware": "camera-11-2-1",
                      "shortName": "MV 11.2.1",
                      "releaseType": "stable",
                      "releaseDate": "2019-03-17T17:22:52Z"
                    }
                  },
                  "nextUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "toVersion": {
                      "id": "2134",
                      "firmware": "camera-15-5-2",
                      "shortName": "MV 25.5.2",
                      "releaseType": "stable",
                      "releaseDate": "2021-05-28T17:22:52Z"
                    }
                  },
                  "isUpgradeAvailable": false,
                  "availableVersions": [
                    {
                      "id": "3421",
                      "firmware": "camera-16-x-y",
                      "shortName": "MV 16.x.y",
                      "releaseType": "beta",
                      "releaseDate": "2020-11-28T17:22:52Z"
                    }
                  ],
                  "participateInNextBetaRelease": false
                },
                "sensor": {
                  "currentVersion": {
                    "id": "4321",
                    "firmware": "camera-11-2-1",
                    "shortName": "MV 11.2.1",
                    "releaseType": "stable",
                    "releaseDate": "2020-03-17T17:22:52Z"
                  },
                  "lastUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "fromVersion": {
                      "id": "1234",
                      "firmware": "camera-10-8-1",
                      "shortName": "MV 10.8.1",
                      "releaseType": "stable",
                      "releaseDate": "2021-03-17T17:22:52Z"
                    },
                    "toVersion": {
                      "id": "4321",
                      "firmware": "camera-11-2-1",
                      "shortName": "MV 11.2.1",
                      "releaseType": "stable",
                      "releaseDate": "2019-03-17T17:22:52Z"
                    }
                  },
                  "nextUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "toVersion": {
                      "id": "2134",
                      "firmware": "camera-15-5-2",
                      "shortName": "MV 25.5.2",
                      "releaseType": "stable",
                      "releaseDate": "2021-05-28T17:22:52Z"
                    }
                  },
                  "isUpgradeAvailable": false,
                  "availableVersions": [
                    {
                      "id": "3421",
                      "firmware": "camera-16-x-y",
                      "shortName": "MV 16.x.y",
                      "releaseType": "beta",
                      "releaseDate": "2020-11-28T17:22:52Z"
                    }
                  ],
                  "participateInNextBetaRelease": false
                },
                "wirelessController": {
                  "currentVersion": {
                    "id": "4321",
                    "firmware": "camera-11-2-1",
                    "shortName": "MV 11.2.1",
                    "releaseType": "stable",
                    "releaseDate": "2020-03-17T17:22:52Z"
                  },
                  "lastUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "fromVersion": {
                      "id": "1234",
                      "firmware": "camera-10-8-1",
                      "shortName": "MV 10.8.1",
                      "releaseType": "stable",
                      "releaseDate": "2021-03-17T17:22:52Z"
                    },
                    "toVersion": {
                      "id": "4321",
                      "firmware": "camera-11-2-1",
                      "shortName": "MV 11.2.1",
                      "releaseType": "stable",
                      "releaseDate": "2019-03-17T17:22:52Z"
                    }
                  },
                  "nextUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "toVersion": {
                      "id": "2134",
                      "firmware": "camera-15-5-2",
                      "shortName": "MV 25.5.2",
                      "releaseType": "stable",
                      "releaseDate": "2021-05-28T17:22:52Z"
                    }
                  },
                  "isUpgradeAvailable": false,
                  "availableVersions": [
                    {
                      "id": "3421",
                      "firmware": "camera-16-x-y",
                      "shortName": "MV 16.x.y",
                      "releaseType": "beta",
                      "releaseDate": "2020-11-28T17:22:52Z"
                    }
                  ],
                  "participateInNextBetaRelease": false
                },
                "secureConnect": {
                  "currentVersion": {
                    "id": "4321",
                    "firmware": "camera-11-2-1",
                    "shortName": "MV 11.2.1",
                    "releaseType": "stable",
                    "releaseDate": "2020-03-17T17:22:52Z"
                  },
                  "lastUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "fromVersion": {
                      "id": "1234",
                      "firmware": "camera-10-8-1",
                      "shortName": "MV 10.8.1",
                      "releaseType": "stable",
                      "releaseDate": "2021-03-17T17:22:52Z"
                    },
                    "toVersion": {
                      "id": "4321",
                      "firmware": "camera-11-2-1",
                      "shortName": "MV 11.2.1",
                      "releaseType": "stable",
                      "releaseDate": "2019-03-17T17:22:52Z"
                    }
                  },
                  "nextUpgrade": {
                    "time": "2021-05-17T17:22:52Z",
                    "toVersion": {
                      "id": "2134",
                      "firmware": "camera-15-5-2",
                      "shortName": "MV 25.5.2",
                      "releaseType": "stable",
                      "releaseDate": "2021-05-28T17:22:52Z"
                    }
                  },
                  "isUpgradeAvailable": false,
                  "availableVersions": [
                    {
                      "id": "3421",
                      "firmware": "camera-16-x-y",
                      "shortName": "MV 16.x.y",
                      "releaseType": "beta",
                      "releaseDate": "2020-11-28T17:22:52Z"
                    }
                  ],
                  "participateInNextBetaRelease": false
                }
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/firmwareUpgrades"

        payload: dict[str, Any] = {}
        if upgrade_window is not None:
            payload["upgradeWindow"] = upgrade_window.model_dump(by_alias=True, exclude_none=True)
        if timezone is not None:
            payload["timezone"] = timezone
        if products is not None:
            payload["products"] = products.model_dump(by_alias=True, exclude_none=True)

        return await self._session.put(
            scope="networks",
            operation_id="updateNetworkFirmwareUpgrades",
            path=path,
            json=payload,
            response_schema=UpdateNetworkFirmwareUpgradesResponse,
        )

    async def create_network_firmware_upgrades_rollback(
        self,
        *,
        network_id: str,
        reasons: list[CreateNetworkFirmwareUpgradesRollbackReasonsItem],
        product: CreateNetworkFirmwareUpgradesRollbackProduct | None = None,
        time: str | None = None,
        to_version: CreateNetworkFirmwareUpgradesRollbackToVersion | None = None,
    ) -> CreateNetworkFirmwareUpgradesRollbackResponse:
        """Rollback a Firmware Upgrade For A Network.

        [API documentation: createNetworkFirmwareUpgradesRollback](https://developer.cisco.com/meraki/api-v1/#!create-network-firmware-upgrades-rollback)

        Args:
            network_id: Network ID.
            product: Product type to rollback (if the network is a combined network).
            time: Scheduled time for the rollback.
            reasons: Reasons for the rollback.
            to_version: Version to downgrade to (if the network has firmware flexibility).

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "product": "switch",
              "status": "pending",
              "upgradeBatchId": "23456",
              "time": "2020-10-21T02:00:00Z",
              "toVersion": {
                "id": "7857",
                "firmware": "switch-15-5-2",
                "shortName": "MS 25.5.2",
                "releaseType": "stable",
                "releaseDate": "2020-03-28T17:22:52Z"
              },
              "reasons": [
                {
                  "category": "performance",
                  "comment": "Network was slower with the upgrade"
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/firmwareUpgrades/rollbacks"

        payload: dict[str, Any] = {}
        if product is not None:
            payload["product"] = product
        if time is not None:
            payload["time"] = time
        if reasons is not None:
            payload["reasons"] = [
                item.model_dump(by_alias=True, exclude_none=True) for item in reasons
            ]
        if to_version is not None:
            payload["toVersion"] = to_version.model_dump(by_alias=True, exclude_none=True)

        return await self._session.post(
            scope="networks",
            operation_id="createNetworkFirmwareUpgradesRollback",
            path=path,
            json=payload,
            response_schema=CreateNetworkFirmwareUpgradesRollbackResponse,
        )

    async def get_network_firmware_upgrades_staged_events(
        self, network_id: str
    ) -> GetNetworkFirmwareUpgradesStagedEventsResponse:
        """Get the Staged Upgrade Event from a network.

        [API documentation: getNetworkFirmwareUpgradesStagedEvents](https://developer.cisco.com/meraki/api-v1/#!get-network-firmware-upgrades-staged-events)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "products": {
                "switch": {
                  "nextUpgrade": {
                    "toVersion": {
                      "id": "1234",
                      "shortName": "MS 15.2.1"
                    }
                  }
                }
              },
              "stages": [
                {
                  "group": {
                    "id": "1234",
                    "name": "My Staged Upgrade Group",
                    "description": "My Staged Upgrade Group Description"
                  },
                  "milestones": {
                    "scheduledFor": "2018-02-11T00:00:00Z",
                    "startedAt": "2018-02-11T00:00:00Z",
                    "completedAt": "2018-02-11T00:00:00Z",
                    "canceledAt": "2018-02-11T00:00:00Z"
                  },
                  "status": "Completed"
                }
              ],
              "reasons": [
                {
                  "category": "performance",
                  "comment": "Network was slower with the upgrade"
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/firmwareUpgrades/staged/events"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkFirmwareUpgradesStagedEvents",
            path=path,
            response_schema=GetNetworkFirmwareUpgradesStagedEventsResponse,
        )

    async def update_network_firmware_upgrades_staged_events(
        self, *, network_id: str, stages: list[UpdateNetworkFirmwareUpgradesStagedEventsStagesItem]
    ) -> UpdateNetworkFirmwareUpgradesStagedEventsResponse:
        """Update the Staged Upgrade Event for a network.

        [API documentation: updateNetworkFirmwareUpgradesStagedEvents](https://developer.cisco.com/meraki/api-v1/#!update-network-firmware-upgrades-staged-events)

        Args:
            network_id: Network ID.
            stages: All firmware upgrade stages in the network with their start time.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "products": {
                "switch": {
                  "nextUpgrade": {
                    "toVersion": {
                      "id": "1234",
                      "shortName": "MS 15.2.1"
                    }
                  }
                }
              },
              "stages": [
                {
                  "group": {
                    "id": "1234",
                    "name": "My Staged Upgrade Group",
                    "description": "My Staged Upgrade Group Description"
                  },
                  "milestones": {
                    "scheduledFor": "2018-02-11T00:00:00Z",
                    "startedAt": "2018-02-11T00:00:00Z",
                    "completedAt": "2018-02-11T00:00:00Z",
                    "canceledAt": "2018-02-11T00:00:00Z"
                  },
                  "status": "Completed"
                }
              ],
              "reasons": [
                {
                  "category": "performance",
                  "comment": "Network was slower with the upgrade"
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/firmwareUpgrades/staged/events"

        payload: dict[str, Any] = {}
        if stages is not None:
            payload["stages"] = [
                item.model_dump(by_alias=True, exclude_none=True) for item in stages
            ]

        return await self._session.put(
            scope="networks",
            operation_id="updateNetworkFirmwareUpgradesStagedEvents",
            path=path,
            json=payload,
            response_schema=UpdateNetworkFirmwareUpgradesStagedEventsResponse,
        )

    async def create_network_firmware_upgrades_staged_event(
        self,
        *,
        network_id: str,
        stages: list[CreateNetworkFirmwareUpgradesStagedEventStagesItem],
        products: CreateNetworkFirmwareUpgradesStagedEventProducts | None = None,
    ) -> CreateNetworkFirmwareUpgradesStagedEventResponse:
        """Create a Staged Upgrade Event for a network.

        [API documentation: createNetworkFirmwareUpgradesStagedEvent](https://developer.cisco.com/meraki/api-v1/#!create-network-firmware-upgrades-staged-event)

        Args:
            network_id: Network ID.
            products: Contains firmware upgrade version information.
            stages: All firmware upgrade stages in the network with their start time.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "products": {
                "switch": {
                  "nextUpgrade": {
                    "toVersion": {
                      "id": "1234",
                      "shortName": "MS 15.2.1"
                    }
                  }
                }
              },
              "stages": [
                {
                  "group": {
                    "id": "1234",
                    "name": "My Staged Upgrade Group",
                    "description": "My Staged Upgrade Group Description"
                  },
                  "milestones": {
                    "scheduledFor": "2018-02-11T00:00:00Z",
                    "startedAt": "2018-02-11T00:00:00Z",
                    "completedAt": "2018-02-11T00:00:00Z",
                    "canceledAt": "2018-02-11T00:00:00Z"
                  },
                  "status": "Completed"
                }
              ],
              "reasons": [
                {
                  "category": "performance",
                  "comment": "Network was slower with the upgrade"
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/firmwareUpgrades/staged/events"

        payload: dict[str, Any] = {}
        if products is not None:
            payload["products"] = products.model_dump(by_alias=True, exclude_none=True)
        if stages is not None:
            payload["stages"] = [
                item.model_dump(by_alias=True, exclude_none=True) for item in stages
            ]

        return await self._session.post(
            scope="networks",
            operation_id="createNetworkFirmwareUpgradesStagedEvent",
            path=path,
            json=payload,
            response_schema=CreateNetworkFirmwareUpgradesStagedEventResponse,
        )

    async def defer_network_firmware_upgrades_staged_events(
        self, network_id: str
    ) -> DeferNetworkFirmwareUpgradesStagedEventsResponse:
        """Postpone by 1 week all pending staged upgrade stages for a network.

        [API documentation: deferNetworkFirmwareUpgradesStagedEvents](https://developer.cisco.com/meraki/api-v1/#!defer-network-firmware-upgrades-staged-events)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "products": {
                "switch": {
                  "nextUpgrade": {
                    "toVersion": {
                      "id": "1234",
                      "shortName": "MS 15.2.1"
                    }
                  }
                }
              },
              "stages": [
                {
                  "group": {
                    "id": "1234",
                    "name": "My Staged Upgrade Group",
                    "description": "My Staged Upgrade Group Description"
                  },
                  "milestones": {
                    "scheduledFor": "2018-02-11T00:00:00Z",
                    "startedAt": "2018-02-11T00:00:00Z",
                    "completedAt": "2018-02-11T00:00:00Z",
                    "canceledAt": "2018-02-11T00:00:00Z"
                  },
                  "status": "Completed"
                }
              ],
              "reasons": [
                {
                  "category": "performance",
                  "comment": "Network was slower with the upgrade"
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/firmwareUpgrades/staged/events/defer"

        return await self._session.post(
            scope="networks",
            operation_id="deferNetworkFirmwareUpgradesStagedEvents",
            path=path,
            response_schema=DeferNetworkFirmwareUpgradesStagedEventsResponse,
        )

    async def rollbacks_network_firmware_upgrades_staged_events(
        self,
        *,
        network_id: str,
        stages: list[RollbacksNetworkFirmwareUpgradesStagedEventsStagesItem],
        reasons: list[RollbacksNetworkFirmwareUpgradesStagedEventsReasonsItem] | None = None,
    ) -> RollbacksNetworkFirmwareUpgradesStagedEventsResponse:
        """Rollback a Staged Upgrade Event for a network.

        [API documentation: rollbacksNetworkFirmwareUpgradesStagedEvents](https://developer.cisco.com/meraki/api-v1/#!rollbacks-network-firmware-upgrades-staged-events)

        Args:
            network_id: Network ID.
            stages: All completed or in-progress stages in the network with their new start times.
                All pending stages will be canceled.
            reasons: The reason for rolling back the staged upgrade.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "products": {
                "switch": {
                  "nextUpgrade": {
                    "toVersion": {
                      "id": "1234",
                      "shortName": "MS 15.2.1"
                    }
                  }
                }
              },
              "stages": [
                {
                  "group": {
                    "id": "1234",
                    "name": "My Staged Upgrade Group",
                    "description": "My Staged Upgrade Group Description"
                  },
                  "milestones": {
                    "scheduledFor": "2018-02-11T00:00:00Z",
                    "startedAt": "2018-02-11T00:00:00Z",
                    "completedAt": "2018-02-11T00:00:00Z",
                    "canceledAt": "2018-02-11T00:00:00Z"
                  },
                  "status": "Completed"
                }
              ],
              "reasons": [
                {
                  "category": "performance",
                  "comment": "Network was slower with the upgrade"
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/firmwareUpgrades/staged/events/rollbacks"

        payload: dict[str, Any] = {}
        if stages is not None:
            payload["stages"] = [
                item.model_dump(by_alias=True, exclude_none=True) for item in stages
            ]
        if reasons is not None:
            payload["reasons"] = [
                item.model_dump(by_alias=True, exclude_none=True) for item in reasons
            ]

        return await self._session.post(
            scope="networks",
            operation_id="rollbacksNetworkFirmwareUpgradesStagedEvents",
            path=path,
            json=payload,
            response_schema=RollbacksNetworkFirmwareUpgradesStagedEventsResponse,
        )

    def get_network_firmware_upgrades_staged_groups(
        self, network_id: str
    ) -> AsyncPaginatedResponse[GetNetworkFirmwareUpgradesStagedGroupsResponseItem]:
        """List of Staged Upgrade Groups in a network.

        [API documentation: getNetworkFirmwareUpgradesStagedGroups](https://developer.cisco.com/meraki/api-v1/#!get-network-firmware-upgrades-staged-groups)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "groupId": "1234",
                "name": "My Staged Upgrade Group",
                "description": "The description of the group",
                "isDefault": false,
                "assignedDevices": {
                  "devices": [
                    {
                      "serial": "Q234-ABCD-5678",
                      "name": "Device Name"
                    }
                  ],
                  "switchStacks": [
                    {
                      "id": "1234",
                      "name": "Stack Name"
                    }
                  ]
                }
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/firmwareUpgrades/staged/groups"

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkFirmwareUpgradesStagedGroups",
            path=path,
            item_schema=GetNetworkFirmwareUpgradesStagedGroupsResponseItem,
        )

    async def create_network_firmware_upgrades_staged_group(
        self,
        *,
        network_id: str,
        name: str,
        is_default: bool,
        description: str | None = None,
        assigned_devices: CreateNetworkFirmwareUpgradesStagedGroupAssignedDevices | None = None,
    ) -> CreateNetworkFirmwareUpgradesStagedGroupResponse:
        """Create a Staged Upgrade Group for a network.

        [API documentation: createNetworkFirmwareUpgradesStagedGroup](https://developer.cisco.com/meraki/api-v1/#!create-network-firmware-upgrades-staged-group)

        Args:
            network_id: Network ID.
            name: Name of the Staged Upgrade Group. Length must be 1 to 255 characters.
            description: Description of the Staged Upgrade Group. Length must be 1 to 255
                characters.
            is_default: Boolean indicating the default Group. Any device that does not have a group
                explicitly assigned will upgrade with this group.
            assigned_devices: The devices and Switch Stacks assigned to the Group.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "groupId": "1234",
              "name": "My Staged Upgrade Group",
              "description": "The description of the group",
              "isDefault": false,
              "assignedDevices": {
                "devices": [
                  {
                    "serial": "Q234-ABCD-5678",
                    "name": "Device Name"
                  }
                ],
                "switchStacks": [
                  {
                    "id": "1234",
                    "name": "Stack Name"
                  }
                ]
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/firmwareUpgrades/staged/groups"

        payload: dict[str, Any] = {}
        if name is not None:
            payload["name"] = name
        if description is not None:
            payload["description"] = description
        if is_default is not None:
            payload["isDefault"] = is_default
        if assigned_devices is not None:
            payload["assignedDevices"] = assigned_devices.model_dump(
                by_alias=True, exclude_none=True
            )

        return await self._session.post(
            scope="networks",
            operation_id="createNetworkFirmwareUpgradesStagedGroup",
            path=path,
            json=payload,
            response_schema=CreateNetworkFirmwareUpgradesStagedGroupResponse,
        )

    async def get_network_firmware_upgrades_staged_group(
        self, *, network_id: str, group_id: str
    ) -> GetNetworkFirmwareUpgradesStagedGroupResponse:
        """Get a Staged Upgrade Group from a network.

        [API documentation: getNetworkFirmwareUpgradesStagedGroup](https://developer.cisco.com/meraki/api-v1/#!get-network-firmware-upgrades-staged-group)

        Args:
            network_id: Network ID.
            group_id: Group ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "groupId": "1234",
              "name": "My Staged Upgrade Group",
              "description": "The description of the group",
              "isDefault": false,
              "assignedDevices": {
                "devices": [
                  {
                    "serial": "Q234-ABCD-5678",
                    "name": "Device Name"
                  }
                ],
                "switchStacks": [
                  {
                    "id": "1234",
                    "name": "Stack Name"
                  }
                ]
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        group_id = urllib.parse.quote(str(group_id), safe="")
        path = f"/networks/{network_id}/firmwareUpgrades/staged/groups/{group_id}"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkFirmwareUpgradesStagedGroup",
            path=path,
            response_schema=GetNetworkFirmwareUpgradesStagedGroupResponse,
        )

    async def update_network_firmware_upgrades_staged_group(
        self,
        *,
        network_id: str,
        group_id: str,
        name: str,
        is_default: bool,
        description: str | None = None,
        assigned_devices: UpdateNetworkFirmwareUpgradesStagedGroupAssignedDevices | None = None,
    ) -> UpdateNetworkFirmwareUpgradesStagedGroupResponse:
        """Update a Staged Upgrade Group for a network.

        [API documentation: updateNetworkFirmwareUpgradesStagedGroup](https://developer.cisco.com/meraki/api-v1/#!update-network-firmware-upgrades-staged-group)

        Args:
            network_id: Network ID.
            group_id: Group ID.
            name: Name of the Staged Upgrade Group. Length must be 1 to 255 characters.
            description: Description of the Staged Upgrade Group. Length must be 1 to 255
                characters.
            is_default: Boolean indicating the default Group. Any device that does not have a group
                explicitly assigned will upgrade with this group.
            assigned_devices: The devices and Switch Stacks assigned to the Group.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "groupId": "1234",
              "name": "My Staged Upgrade Group",
              "description": "The description of the group",
              "isDefault": false,
              "assignedDevices": {
                "devices": [
                  {
                    "serial": "Q234-ABCD-5678",
                    "name": "Device Name"
                  }
                ],
                "switchStacks": [
                  {
                    "id": "1234",
                    "name": "Stack Name"
                  }
                ]
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        group_id = urllib.parse.quote(str(group_id), safe="")
        path = f"/networks/{network_id}/firmwareUpgrades/staged/groups/{group_id}"

        payload: dict[str, Any] = {}
        if name is not None:
            payload["name"] = name
        if description is not None:
            payload["description"] = description
        if is_default is not None:
            payload["isDefault"] = is_default
        if assigned_devices is not None:
            payload["assignedDevices"] = assigned_devices.model_dump(
                by_alias=True, exclude_none=True
            )

        return await self._session.put(
            scope="networks",
            operation_id="updateNetworkFirmwareUpgradesStagedGroup",
            path=path,
            json=payload,
            response_schema=UpdateNetworkFirmwareUpgradesStagedGroupResponse,
        )

    async def delete_network_firmware_upgrades_staged_group(
        self, *, network_id: str, group_id: str
    ) -> None:
        """Delete a Staged Upgrade Group.

        [API documentation: deleteNetworkFirmwareUpgradesStagedGroup](https://developer.cisco.com/meraki/api-v1/#!delete-network-firmware-upgrades-staged-group)

        Args:
            network_id: Network ID.
            group_id: Group ID.

        Returns:
            Successful operation.

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        group_id = urllib.parse.quote(str(group_id), safe="")
        path = f"/networks/{network_id}/firmwareUpgrades/staged/groups/{group_id}"

        return await self._session.delete(
            scope="networks", operation_id="deleteNetworkFirmwareUpgradesStagedGroup", path=path
        )

    def get_network_firmware_upgrades_staged_stages(
        self, network_id: str
    ) -> AsyncPaginatedResponse[GetNetworkFirmwareUpgradesStagedStagesResponseItem]:
        """Order of Staged Upgrade Groups in a network.

        [API documentation: getNetworkFirmwareUpgradesStagedStages](https://developer.cisco.com/meraki/api-v1/#!get-network-firmware-upgrades-staged-stages)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "group": {
                  "id": "1234",
                  "name": "My Staged Upgrade Group",
                  "description": "My Staged Upgrade Description"
                }
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/firmwareUpgrades/staged/stages"

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkFirmwareUpgradesStagedStages",
            path=path,
            item_schema=GetNetworkFirmwareUpgradesStagedStagesResponseItem,
        )

    async def update_network_firmware_upgrades_staged_stages(
        self,
        network_id: str,
        *,
        _json: list[UpdateNetworkFirmwareUpgradesStagedStagesJsonItem] | None = None,
    ) -> UpdateNetworkFirmwareUpgradesStagedStagesResponse:
        """Assign Staged Upgrade Group order in the sequence.

        [API documentation: updateNetworkFirmwareUpgradesStagedStages](https://developer.cisco.com/meraki/api-v1/#!update-network-firmware-upgrades-staged-stages)

        Args:
            network_id: Network ID.
            _json: Array of Staged Upgrade Groups.

        Returns:
            Successful operation.

        Example API response:
            ```json
            [
              {
                "group": {
                  "id": "1234",
                  "name": "My Staged Upgrade Group",
                  "description": "My Staged Upgrade Description"
                }
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/firmwareUpgrades/staged/stages"

        payload: dict[str, Any] = {}
        if _json is not None:
            payload["_json"] = [item.model_dump(by_alias=True, exclude_none=True) for item in _json]

        return await self._session.put(
            scope="networks",
            operation_id="updateNetworkFirmwareUpgradesStagedStages",
            path=path,
            json=payload,
            response_schema=UpdateNetworkFirmwareUpgradesStagedStagesResponse,
        )

    def get_network_floor_plans(
        self, network_id: str
    ) -> AsyncPaginatedResponse[GetNetworkFloorPlansResponseItem]:
        """List the floor plans that belong to your network.

        [API documentation: getNetworkFloorPlans](https://developer.cisco.com/meraki/api-v1/#!get-network-floor-plans)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "floorPlanId": "g_1234567",
                "imageUrl": "https://meraki-na.s3.amazonaws.com/assets/...",
                "imageUrlExpiresAt": "2019-06-11 16:04:54 +00:00",
                "imageExtension": "png",
                "imageMd5": "2a9edd3f4ffd80130c647d13eacb59f3",
                "name": "HQ Floor Plan",
                "devices": [
                  {
                    "name": "My AP",
                    "lat": 37.4180951010362,
                    "lng": -122.098531723022,
                    "address": "1600 Pennsylvania Ave",
                    "notes": "My AP's note",
                    "tags": [
                      "recently-added"
                    ],
                    "networkId": "N_24329156",
                    "serial": "Q234-ABCD-5678",
                    "model": "MR34",
                    "imei": "123456789000000",
                    "mac": "00:11:22:33:44:55",
                    "lanIp": "1.2.3.4",
                    "firmware": "wireless-25-14",
                    "productType": "wireless",
                    "details": [
                      {
                        "name": "Catalyst serial",
                        "value": "123ABC"
                      }
                    ]
                  }
                ],
                "width": 100.0,
                "height": 150.1,
                "center": {
                  "lat": 37.770040510499996,
                  "lng": -122.38714009525
                },
                "bottomLeftCorner": {
                  "lat": 37.7696461495,
                  "lng": -122.3880815506
                },
                "bottomRightCorner": {
                  "lat": 37.771524649766654,
                  "lng": -122.38795275055205
                },
                "topLeftCorner": {
                  "lat": 37.769700101836364,
                  "lng": -122.3888684251381
                },
                "topRightCorner": {
                  "lat": 37.77157860210302,
                  "lng": -122.38873962509012
                },
                "floorNumber": 5.0
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/floorPlans"

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkFloorPlans",
            path=path,
            item_schema=GetNetworkFloorPlansResponseItem,
        )

    async def create_network_floor_plan(
        self,
        *,
        network_id: str,
        name: str,
        image_contents: str,
        center: CreateNetworkFloorPlanCenter | None = None,
        bottom_left_corner: CreateNetworkFloorPlanBottomLeftCorner | None = None,
        bottom_right_corner: CreateNetworkFloorPlanBottomRightCorner | None = None,
        top_left_corner: CreateNetworkFloorPlanTopLeftCorner | None = None,
        top_right_corner: CreateNetworkFloorPlanTopRightCorner | None = None,
        floor_number: float | None = None,
    ) -> CreateNetworkFloorPlanResponse:
        """Upload a floor plan.

        [API documentation: createNetworkFloorPlan](https://developer.cisco.com/meraki/api-v1/#!create-network-floor-plan)

        Args:
            network_id: Network ID.
            name: The name of your floor plan.
            center: The longitude and latitude of the center of your floor plan. The 'center' or two
                adjacent corners (e.g. 'topLeftCorner' and 'bottomLeftCorner') must be
                specified. If 'center' is specified, the floor plan is placed over that
                point with no rotation. If two adjacent corners are specified, the floor
                plan is rotated to line up with the two specified points. The aspect
                ratio of the floor plan's image is preserved regardless of which
                corners/center are specified. (This means if that more than two corners
                are specified, only two corners may be used to preserve the floor plan's
                aspect ratio.). No two points can have the same latitude, longitude
                pair.
            bottom_left_corner: The longitude and latitude of the bottom left corner of your floor
                plan.
            bottom_right_corner: The longitude and latitude of the bottom right corner of your floor
                plan.
            top_left_corner: The longitude and latitude of the top left corner of your floor plan.
            top_right_corner: The longitude and latitude of the top right corner of your floor plan.
            floor_number: The floor number of the floors within the building.
            image_contents: The file contents (a base 64 encoded string) of your image. Supported
                formats are PNG, GIF, and JPG. Note that all images are saved as PNG
                files, regardless of the format they are uploaded in.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "floorPlanId": "g_1234567",
              "imageUrl": "https://meraki-na.s3.amazonaws.com/assets/...",
              "imageUrlExpiresAt": "2019-06-11 16:04:54 +00:00",
              "imageExtension": "png",
              "imageMd5": "2a9edd3f4ffd80130c647d13eacb59f3",
              "name": "HQ Floor Plan",
              "devices": [
                {
                  "name": "My AP",
                  "lat": 37.4180951010362,
                  "lng": -122.098531723022,
                  "address": "1600 Pennsylvania Ave",
                  "notes": "My AP's note",
                  "tags": [
                    "recently-added"
                  ],
                  "networkId": "N_24329156",
                  "serial": "Q234-ABCD-5678",
                  "model": "MR34",
                  "imei": "123456789000000",
                  "mac": "00:11:22:33:44:55",
                  "lanIp": "1.2.3.4",
                  "firmware": "wireless-25-14",
                  "productType": "wireless",
                  "details": [
                    {
                      "name": "Catalyst serial",
                      "value": "123ABC"
                    }
                  ]
                }
              ],
              "width": 100.0,
              "height": 150.1,
              "center": {
                "lat": 37.770040510499996,
                "lng": -122.38714009525
              },
              "bottomLeftCorner": {
                "lat": 37.7696461495,
                "lng": -122.3880815506
              },
              "bottomRightCorner": {
                "lat": 37.771524649766654,
                "lng": -122.38795275055205
              },
              "topLeftCorner": {
                "lat": 37.769700101836364,
                "lng": -122.3888684251381
              },
              "topRightCorner": {
                "lat": 37.77157860210302,
                "lng": -122.38873962509012
              },
              "floorNumber": 5.0
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/floorPlans"

        payload: dict[str, Any] = {}
        if name is not None:
            payload["name"] = name
        if center is not None:
            payload["center"] = center.model_dump(by_alias=True, exclude_none=True)
        if bottom_left_corner is not None:
            payload["bottomLeftCorner"] = bottom_left_corner.model_dump(
                by_alias=True, exclude_none=True
            )
        if bottom_right_corner is not None:
            payload["bottomRightCorner"] = bottom_right_corner.model_dump(
                by_alias=True, exclude_none=True
            )
        if top_left_corner is not None:
            payload["topLeftCorner"] = top_left_corner.model_dump(by_alias=True, exclude_none=True)
        if top_right_corner is not None:
            payload["topRightCorner"] = top_right_corner.model_dump(
                by_alias=True, exclude_none=True
            )
        if floor_number is not None:
            payload["floorNumber"] = floor_number
        if image_contents is not None:
            payload["imageContents"] = image_contents

        return await self._session.post(
            scope="networks",
            operation_id="createNetworkFloorPlan",
            path=path,
            json=payload,
            response_schema=CreateNetworkFloorPlanResponse,
        )

    async def batch_network_floor_plans_auto_locate_jobs(
        self, *, network_id: str, jobs: list[BatchNetworkFloorPlansAutoLocateJobsJobsItem]
    ) -> BatchNetworkFloorPlansAutoLocateJobsResponse:
        """Schedule auto locate jobs for one or more floor plans in a network.

        [API documentation: batchNetworkFloorPlansAutoLocateJobs](https://developer.cisco.com/meraki/api-v1/#!batch-network-floor-plans-auto-locate-jobs)

        Args:
            network_id: Network ID.
            jobs: The list of auto locate jobs to be scheduled. Up to 100 jobs can be provided in a
                request.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "jobs": [
                {
                  "id": "1234",
                  "networkId": "N_24329156",
                  "floorPlanId": "g_2176982374",
                  "status": "error",
                  "scheduledAt": "2018-02-11T00:00:00Z",
                  "completed": {
                    "percentage": 50
                  },
                  "ranging": {
                    "status": "in progress",
                    "completed": {
                      "percentage": 24
                    }
                  },
                  "gnss": {
                    "status": "in progress",
                    "completed": {
                      "percentage": 4
                    }
                  },
                  "errors": [
                    {
                      "source": "ranging",
                      "type": "missing anchors"
                    }
                  ]
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/floorPlans/autoLocate/jobs/batch"

        payload: dict[str, Any] = {}
        if jobs is not None:
            payload["jobs"] = [item.model_dump(by_alias=True, exclude_none=True) for item in jobs]

        return await self._session.post(
            scope="networks",
            operation_id="batchNetworkFloorPlansAutoLocateJobs",
            path=path,
            json=payload,
            response_schema=BatchNetworkFloorPlansAutoLocateJobsResponse,
        )

    async def cancel_network_floor_plans_auto_locate_job(
        self, *, network_id: str, job_id: str
    ) -> None:
        """Cancel a scheduled or running auto locate job.

        [API documentation: cancelNetworkFloorPlansAutoLocateJob](https://developer.cisco.com/meraki/api-v1/#!cancel-network-floor-plans-auto-locate-job)

        Args:
            network_id: Network ID.
            job_id: Job ID.

        Returns:
            Successful operation.

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        job_id = urllib.parse.quote(str(job_id), safe="")
        path = f"/networks/{network_id}/floorPlans/autoLocate/jobs/{job_id}/cancel"

        return await self._session.post(
            scope="networks", operation_id="cancelNetworkFloorPlansAutoLocateJob", path=path
        )

    async def publish_network_floor_plans_auto_locate_job(
        self,
        *,
        network_id: str,
        job_id: str,
        devices: list[PublishNetworkFloorPlansAutoLocateJobDevicesItem] | None = None,
    ) -> PublishNetworkFloorPlansAutoLocateJobResponse:
        """Update the status of a finished auto locate job to be published, and update device locations.

        [API documentation: publishNetworkFloorPlansAutoLocateJob](https://developer.cisco.com/meraki/api-v1/#!publish-network-floor-plans-auto-locate-job)

        Args:
            network_id: Network ID.
            job_id: Job ID.
            devices: The list of devices to publish positions for.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "success": true
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        job_id = urllib.parse.quote(str(job_id), safe="")
        path = f"/networks/{network_id}/floorPlans/autoLocate/jobs/{job_id}/publish"

        payload: dict[str, Any] = {}
        if devices is not None:
            payload["devices"] = [
                item.model_dump(by_alias=True, exclude_none=True) for item in devices
            ]

        return await self._session.post(
            scope="networks",
            operation_id="publishNetworkFloorPlansAutoLocateJob",
            path=path,
            json=payload,
            response_schema=PublishNetworkFloorPlansAutoLocateJobResponse,
        )

    async def recalculate_network_floor_plans_auto_locate_job(
        self,
        *,
        network_id: str,
        job_id: str,
        devices: list[RecalculateNetworkFloorPlansAutoLocateJobDevicesItem] | None = None,
    ) -> RecalculateNetworkFloorPlansAutoLocateJobResponse:
        """Trigger auto locate recalculation for a job, and optionally set anchors.

        [API documentation: recalculateNetworkFloorPlansAutoLocateJob](https://developer.cisco.com/meraki/api-v1/#!recalculate-network-floor-plans-auto-locate-job)

        Args:
            network_id: Network ID.
            job_id: Job ID.
            devices: The list of devices to update anchor positions for.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "success": true
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        job_id = urllib.parse.quote(str(job_id), safe="")
        path = f"/networks/{network_id}/floorPlans/autoLocate/jobs/{job_id}/recalculate"

        payload: dict[str, Any] = {}
        if devices is not None:
            payload["devices"] = [
                item.model_dump(by_alias=True, exclude_none=True) for item in devices
            ]

        return await self._session.post(
            scope="networks",
            operation_id="recalculateNetworkFloorPlansAutoLocateJob",
            path=path,
            json=payload,
            response_schema=RecalculateNetworkFloorPlansAutoLocateJobResponse,
        )

    async def batch_network_floor_plans_devices_update(
        self,
        *,
        network_id: str,
        assignments: list[BatchNetworkFloorPlansDevicesUpdateAssignmentsItem],
    ) -> BatchNetworkFloorPlansDevicesUpdateResponse:
        """Update floorplan assignments for a batch of devices.

        [API documentation: batchNetworkFloorPlansDevicesUpdate](https://developer.cisco.com/meraki/api-v1/#!batch-network-floor-plans-devices-update)

        Args:
            network_id: Network ID.
            assignments: List of floorplan assignments to update. Up to 100 floor plan assignments
                can be provided in a request.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "success": true
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/floorPlans/devices/batchUpdate"

        payload: dict[str, Any] = {}
        if assignments is not None:
            payload["assignments"] = [
                item.model_dump(by_alias=True, exclude_none=True) for item in assignments
            ]

        return await self._session.post(
            scope="networks",
            operation_id="batchNetworkFloorPlansDevicesUpdate",
            path=path,
            json=payload,
            response_schema=BatchNetworkFloorPlansDevicesUpdateResponse,
        )

    async def get_network_floor_plan(
        self, *, network_id: str, floor_plan_id: str
    ) -> GetNetworkFloorPlanResponse:
        """Find a floor plan by ID.

        [API documentation: getNetworkFloorPlan](https://developer.cisco.com/meraki/api-v1/#!get-network-floor-plan)

        Args:
            network_id: Network ID.
            floor_plan_id: Floor plan ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "floorPlanId": "g_1234567",
              "imageUrl": "https://meraki-na.s3.amazonaws.com/assets/...",
              "imageUrlExpiresAt": "2019-06-11 16:04:54 +00:00",
              "imageExtension": "png",
              "imageMd5": "2a9edd3f4ffd80130c647d13eacb59f3",
              "name": "HQ Floor Plan",
              "devices": [
                {
                  "name": "My AP",
                  "lat": 37.4180951010362,
                  "lng": -122.098531723022,
                  "address": "1600 Pennsylvania Ave",
                  "notes": "My AP's note",
                  "tags": [
                    "recently-added"
                  ],
                  "networkId": "N_24329156",
                  "serial": "Q234-ABCD-5678",
                  "model": "MR34",
                  "imei": "123456789000000",
                  "mac": "00:11:22:33:44:55",
                  "lanIp": "1.2.3.4",
                  "firmware": "wireless-25-14",
                  "productType": "wireless",
                  "details": [
                    {
                      "name": "Catalyst serial",
                      "value": "123ABC"
                    }
                  ]
                }
              ],
              "width": 100.0,
              "height": 150.1,
              "center": {
                "lat": 37.770040510499996,
                "lng": -122.38714009525
              },
              "bottomLeftCorner": {
                "lat": 37.7696461495,
                "lng": -122.3880815506
              },
              "bottomRightCorner": {
                "lat": 37.771524649766654,
                "lng": -122.38795275055205
              },
              "topLeftCorner": {
                "lat": 37.769700101836364,
                "lng": -122.3888684251381
              },
              "topRightCorner": {
                "lat": 37.77157860210302,
                "lng": -122.38873962509012
              },
              "floorNumber": 5.0
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        floor_plan_id = urllib.parse.quote(str(floor_plan_id), safe="")
        path = f"/networks/{network_id}/floorPlans/{floor_plan_id}"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkFloorPlan",
            path=path,
            response_schema=GetNetworkFloorPlanResponse,
        )

    async def update_network_floor_plan(
        self,
        *,
        network_id: str,
        floor_plan_id: str,
        name: str | None = None,
        center: UpdateNetworkFloorPlanCenter | None = None,
        bottom_left_corner: UpdateNetworkFloorPlanBottomLeftCorner | None = None,
        bottom_right_corner: UpdateNetworkFloorPlanBottomRightCorner | None = None,
        top_left_corner: UpdateNetworkFloorPlanTopLeftCorner | None = None,
        top_right_corner: UpdateNetworkFloorPlanTopRightCorner | None = None,
        floor_number: float | None = None,
        image_contents: str | None = None,
    ) -> UpdateNetworkFloorPlanResponse:
        """Update a floor plan's geolocation and other meta data.

        [API documentation: updateNetworkFloorPlan](https://developer.cisco.com/meraki/api-v1/#!update-network-floor-plan)

        Args:
            network_id: Network ID.
            floor_plan_id: Floor plan ID.
            name: The name of your floor plan.
            center: The longitude and latitude of the center of your floor plan. If you want to
                change the geolocation data of your floor plan, either the 'center' or
                two adjacent corners (e.g. 'topLeftCorner' and 'bottomLeftCorner') must
                be specified. If 'center' is specified, the floor plan is placed over
                that point with no rotation. If two adjacent corners are specified, the
                floor plan is rotated to line up with the two specified points. The
                aspect ratio of the floor plan's image is preserved regardless of which
                corners/center are specified. (This means if that more than two corners
                are specified, only two corners may be used to preserve the floor plan's
                aspect ratio.). No two points can have the same latitude, longitude
                pair.
            bottom_left_corner: The longitude and latitude of the bottom left corner of your floor
                plan.
            bottom_right_corner: The longitude and latitude of the bottom right corner of your floor
                plan.
            top_left_corner: The longitude and latitude of the top left corner of your floor plan.
            top_right_corner: The longitude and latitude of the top right corner of your floor plan.
            floor_number: The floor number of the floors within the building.
            image_contents: The file contents (a base 64 encoded string) of your new image.
                Supported formats are PNG, GIF, and JPG. Note that all images are saved
                as PNG files, regardless of the format they are uploaded in. If you
                upload a new image, and you do NOT specify any new geolocation fields
                ('center, 'topLeftCorner', etc), the floor plan will be recentered with
                no rotation in order to maintain the aspect ratio of your new image.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "floorPlanId": "g_1234567",
              "imageUrl": "https://meraki-na.s3.amazonaws.com/assets/...",
              "imageUrlExpiresAt": "2019-06-11 16:04:54 +00:00",
              "imageExtension": "png",
              "imageMd5": "2a9edd3f4ffd80130c647d13eacb59f3",
              "name": "HQ Floor Plan",
              "devices": [
                {
                  "name": "My AP",
                  "lat": 37.4180951010362,
                  "lng": -122.098531723022,
                  "address": "1600 Pennsylvania Ave",
                  "notes": "My AP's note",
                  "tags": [
                    "recently-added"
                  ],
                  "networkId": "N_24329156",
                  "serial": "Q234-ABCD-5678",
                  "model": "MR34",
                  "imei": "123456789000000",
                  "mac": "00:11:22:33:44:55",
                  "lanIp": "1.2.3.4",
                  "firmware": "wireless-25-14",
                  "productType": "wireless",
                  "details": [
                    {
                      "name": "Catalyst serial",
                      "value": "123ABC"
                    }
                  ]
                }
              ],
              "width": 100.0,
              "height": 150.1,
              "center": {
                "lat": 37.770040510499996,
                "lng": -122.38714009525
              },
              "bottomLeftCorner": {
                "lat": 37.7696461495,
                "lng": -122.3880815506
              },
              "bottomRightCorner": {
                "lat": 37.771524649766654,
                "lng": -122.38795275055205
              },
              "topLeftCorner": {
                "lat": 37.769700101836364,
                "lng": -122.3888684251381
              },
              "topRightCorner": {
                "lat": 37.77157860210302,
                "lng": -122.38873962509012
              },
              "floorNumber": 5.0
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        floor_plan_id = urllib.parse.quote(str(floor_plan_id), safe="")
        path = f"/networks/{network_id}/floorPlans/{floor_plan_id}"

        payload: dict[str, Any] = {}
        if name is not None:
            payload["name"] = name
        if center is not None:
            payload["center"] = center.model_dump(by_alias=True, exclude_none=True)
        if bottom_left_corner is not None:
            payload["bottomLeftCorner"] = bottom_left_corner.model_dump(
                by_alias=True, exclude_none=True
            )
        if bottom_right_corner is not None:
            payload["bottomRightCorner"] = bottom_right_corner.model_dump(
                by_alias=True, exclude_none=True
            )
        if top_left_corner is not None:
            payload["topLeftCorner"] = top_left_corner.model_dump(by_alias=True, exclude_none=True)
        if top_right_corner is not None:
            payload["topRightCorner"] = top_right_corner.model_dump(
                by_alias=True, exclude_none=True
            )
        if floor_number is not None:
            payload["floorNumber"] = floor_number
        if image_contents is not None:
            payload["imageContents"] = image_contents

        return await self._session.put(
            scope="networks",
            operation_id="updateNetworkFloorPlan",
            path=path,
            json=payload,
            response_schema=UpdateNetworkFloorPlanResponse,
        )

    async def delete_network_floor_plan(self, *, network_id: str, floor_plan_id: str) -> None:
        """Destroy a floor plan.

        [API documentation: deleteNetworkFloorPlan](https://developer.cisco.com/meraki/api-v1/#!delete-network-floor-plan)

        Args:
            network_id: Network ID.
            floor_plan_id: Floor plan ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "floorPlanId": "g_1234567",
              "imageUrl": "https://meraki-na.s3.amazonaws.com/assets/...",
              "imageUrlExpiresAt": "2019-06-11 16:04:54 +00:00",
              "imageExtension": "png",
              "imageMd5": "2a9edd3f4ffd80130c647d13eacb59f3",
              "name": "HQ Floor Plan",
              "devices": [
                {
                  "name": "My AP",
                  "lat": 37.4180951010362,
                  "lng": -122.098531723022,
                  "address": "1600 Pennsylvania Ave",
                  "notes": "My AP's note",
                  "tags": [
                    "recently-added"
                  ],
                  "networkId": "N_24329156",
                  "serial": "Q234-ABCD-5678",
                  "model": "MR34",
                  "imei": "123456789000000",
                  "mac": "00:11:22:33:44:55",
                  "lanIp": "1.2.3.4",
                  "firmware": "wireless-25-14",
                  "productType": "wireless",
                  "details": [
                    {
                      "name": "Catalyst serial",
                      "value": "123ABC"
                    }
                  ]
                }
              ],
              "width": 100.0,
              "height": 150.1,
              "center": {
                "lat": 37.770040510499996,
                "lng": -122.38714009525
              },
              "bottomLeftCorner": {
                "lat": 37.7696461495,
                "lng": -122.3880815506
              },
              "bottomRightCorner": {
                "lat": 37.771524649766654,
                "lng": -122.38795275055205
              },
              "topLeftCorner": {
                "lat": 37.769700101836364,
                "lng": -122.3888684251381
              },
              "topRightCorner": {
                "lat": 37.77157860210302,
                "lng": -122.38873962509012
              },
              "floorNumber": 5.0
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        floor_plan_id = urllib.parse.quote(str(floor_plan_id), safe="")
        path = f"/networks/{network_id}/floorPlans/{floor_plan_id}"

        return await self._session.delete(
            scope="networks", operation_id="deleteNetworkFloorPlan", path=path
        )

    def get_network_group_policies(
        self, network_id: str
    ) -> AsyncPaginatedResponse[GetNetworkGroupPoliciesResponseItem]:
        """List the group policies in a network.

        [API documentation: getNetworkGroupPolicies](https://developer.cisco.com/meraki/api-v1/#!get-network-group-policies)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "groupPolicyId": "101",
                "scheduling": {
                  "enabled": true,
                  "monday": {
                    "active": true,
                    "from": "9:00",
                    "to": "17:00"
                  },
                  "tuesday": {
                    "active": true,
                    "from": "9:00",
                    "to": "17:00"
                  },
                  "wednesday": {
                    "active": true,
                    "from": "9:00",
                    "to": "17:00"
                  },
                  "thursday": {
                    "active": true,
                    "from": "9:00",
                    "to": "17:00"
                  },
                  "friday": {
                    "active": true,
                    "from": "9:00",
                    "to": "17:00"
                  },
                  "saturday": {
                    "active": true,
                    "from": "9:00",
                    "to": "17:00"
                  },
                  "sunday": {
                    "active": true,
                    "from": "9:00",
                    "to": "17:00"
                  }
                },
                "bandwidth": {
                  "settings": "custom",
                  "bandwidthLimits": {
                    "limitUp": 1000000,
                    "limitDown": 1000000
                  }
                },
                "firewallAndTrafficShaping": {
                  "settings": "custom",
                  "trafficShapingRules": [
                    {
                      "definitions": [
                        {
                          "type": "host",
                          "value": "google.com"
                        }
                      ],
                      "perClientBandwidthLimits": {
                        "settings": "custom",
                        "bandwidthLimits": {
                          "limitUp": 1000000,
                          "limitDown": 1000000
                        }
                      },
                      "dscpTagValue": 0,
                      "pcpTagValue": 0,
                      "priority": "normal"
                    }
                  ],
                  "l3FirewallRules": [
                    {
                      "comment": "Allow TCP traffic to subnet with HTTP servers.",
                      "policy": "allow",
                      "protocol": "tcp",
                      "destPort": "443",
                      "destCidr": "192.168.1.0/24"
                    }
                  ],
                  "l7FirewallRules": [
                    {
                      "policy": "deny",
                      "type": "host",
                      "value": "google.com"
                    }
                  ]
                },
                "contentFiltering": {
                  "allowedUrlPatterns": {
                    "settings": "network default",
                    "patterns": []
                  },
                  "blockedUrlPatterns": {
                    "settings": "append",
                    "patterns": [
                      "http://www.example.com",
                      "http://www.betting.com"
                    ]
                  },
                  "blockedUrlCategories": {
                    "settings": "override",
                    "categories": [
                      "meraki:contentFiltering/category/1",
                      "meraki:contentFiltering/category/7"
                    ]
                  }
                },
                "splashAuthSettings": "bypass",
                "vlanTagging": {
                  "settings": "custom",
                  "vlanId": "1"
                },
                "bonjourForwarding": {
                  "settings": "custom",
                  "rules": [
                    {
                      "description": "A simple bonjour rule",
                      "vlanId": "1",
                      "services": [
                        "All Services"
                      ]
                    }
                  ]
                }
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/groupPolicies"

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkGroupPolicies",
            path=path,
            item_schema=GetNetworkGroupPoliciesResponseItem,
        )

    async def create_network_group_policy(
        self,
        *,
        network_id: str,
        name: str,
        scheduling: CreateNetworkGroupPolicyScheduling | None = None,
        bandwidth: CreateNetworkGroupPolicyBandwidth | None = None,
        firewall_and_traffic_shaping: CreateNetworkGroupPolicyFirewallAndTrafficShaping
        | None = None,
        content_filtering: CreateNetworkGroupPolicyContentFiltering | None = None,
        splash_auth_settings: CreateNetworkGroupPolicySplashAuthSettings | None = None,
        vlan_tagging: CreateNetworkGroupPolicyVlanTagging | None = None,
        bonjour_forwarding: CreateNetworkGroupPolicyBonjourForwarding | None = None,
    ) -> CreateNetworkGroupPolicyResponse:
        """Create a group policy.

        [API documentation: createNetworkGroupPolicy](https://developer.cisco.com/meraki/api-v1/#!create-network-group-policy)

        Args:
            network_id: Network ID.
            name: The name for your group policy. Required.
            scheduling: The schedule for the group policy. Schedules are applied to days of the
                week.
            bandwidth: The bandwidth settings for clients bound to your group policy.
            firewall_and_traffic_shaping: The firewall and traffic shaping rules and settings for
                your policy.
            content_filtering: The content filtering settings for your group policy.
            splash_auth_settings: Whether clients bound to your policy will bypass splash
                authorization or behave according to the network's rules. Can be one of
                'network default' or 'bypass'. Only available if your network has a
                wireless configuration.
            vlan_tagging: The VLAN tagging settings for your group policy. Only available if your
                network has a wireless configuration.
            bonjour_forwarding: The Bonjour settings for your group policy. Only valid if your
                network has a wireless configuration.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "groupPolicyId": "101",
              "scheduling": {
                "enabled": true,
                "monday": {
                  "active": true,
                  "from": "9:00",
                  "to": "17:00"
                },
                "tuesday": {
                  "active": true,
                  "from": "9:00",
                  "to": "17:00"
                },
                "wednesday": {
                  "active": true,
                  "from": "9:00",
                  "to": "17:00"
                },
                "thursday": {
                  "active": true,
                  "from": "9:00",
                  "to": "17:00"
                },
                "friday": {
                  "active": true,
                  "from": "9:00",
                  "to": "17:00"
                },
                "saturday": {
                  "active": true,
                  "from": "9:00",
                  "to": "17:00"
                },
                "sunday": {
                  "active": true,
                  "from": "9:00",
                  "to": "17:00"
                }
              },
              "bandwidth": {
                "settings": "custom",
                "bandwidthLimits": {
                  "limitUp": 1000000,
                  "limitDown": 1000000
                }
              },
              "firewallAndTrafficShaping": {
                "settings": "custom",
                "trafficShapingRules": [
                  {
                    "definitions": [
                      {
                        "type": "host",
                        "value": "google.com"
                      }
                    ],
                    "perClientBandwidthLimits": {
                      "settings": "custom",
                      "bandwidthLimits": {
                        "limitUp": 1000000,
                        "limitDown": 1000000
                      }
                    },
                    "dscpTagValue": 0,
                    "pcpTagValue": 0,
                    "priority": "normal"
                  }
                ],
                "l3FirewallRules": [
                  {
                    "comment": "Allow TCP traffic to subnet with HTTP servers.",
                    "policy": "allow",
                    "protocol": "tcp",
                    "destPort": "443",
                    "destCidr": "192.168.1.0/24"
                  }
                ],
                "l7FirewallRules": [
                  {
                    "policy": "deny",
                    "type": "host",
                    "value": "google.com"
                  }
                ]
              },
              "contentFiltering": {
                "allowedUrlPatterns": {
                  "settings": "network default",
                  "patterns": []
                },
                "blockedUrlPatterns": {
                  "settings": "append",
                  "patterns": [
                    "http://www.example.com",
                    "http://www.betting.com"
                  ]
                },
                "blockedUrlCategories": {
                  "settings": "override",
                  "categories": [
                    "meraki:contentFiltering/category/1",
                    "meraki:contentFiltering/category/7"
                  ]
                }
              },
              "splashAuthSettings": "bypass",
              "vlanTagging": {
                "settings": "custom",
                "vlanId": "1"
              },
              "bonjourForwarding": {
                "settings": "custom",
                "rules": [
                  {
                    "description": "A simple bonjour rule",
                    "vlanId": "1",
                    "services": [
                      "All Services"
                    ]
                  }
                ]
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/groupPolicies"

        payload: dict[str, Any] = {}
        if name is not None:
            payload["name"] = name
        if scheduling is not None:
            payload["scheduling"] = scheduling.model_dump(by_alias=True, exclude_none=True)
        if bandwidth is not None:
            payload["bandwidth"] = bandwidth.model_dump(by_alias=True, exclude_none=True)
        if firewall_and_traffic_shaping is not None:
            payload["firewallAndTrafficShaping"] = firewall_and_traffic_shaping.model_dump(
                by_alias=True, exclude_none=True
            )
        if content_filtering is not None:
            payload["contentFiltering"] = content_filtering.model_dump(
                by_alias=True, exclude_none=True
            )
        if splash_auth_settings is not None:
            payload["splashAuthSettings"] = splash_auth_settings
        if vlan_tagging is not None:
            payload["vlanTagging"] = vlan_tagging.model_dump(by_alias=True, exclude_none=True)
        if bonjour_forwarding is not None:
            payload["bonjourForwarding"] = bonjour_forwarding.model_dump(
                by_alias=True, exclude_none=True
            )

        return await self._session.post(
            scope="networks",
            operation_id="createNetworkGroupPolicy",
            path=path,
            json=payload,
            response_schema=CreateNetworkGroupPolicyResponse,
        )

    async def get_network_group_policy(
        self, *, network_id: str, group_policy_id: str
    ) -> GetNetworkGroupPolicyResponse:
        """Display a group policy.

        [API documentation: getNetworkGroupPolicy](https://developer.cisco.com/meraki/api-v1/#!get-network-group-policy)

        Args:
            network_id: Network ID.
            group_policy_id: Group policy ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "groupPolicyId": "101",
              "scheduling": {
                "enabled": true,
                "monday": {
                  "active": true,
                  "from": "9:00",
                  "to": "17:00"
                },
                "tuesday": {
                  "active": true,
                  "from": "9:00",
                  "to": "17:00"
                },
                "wednesday": {
                  "active": true,
                  "from": "9:00",
                  "to": "17:00"
                },
                "thursday": {
                  "active": true,
                  "from": "9:00",
                  "to": "17:00"
                },
                "friday": {
                  "active": true,
                  "from": "9:00",
                  "to": "17:00"
                },
                "saturday": {
                  "active": true,
                  "from": "9:00",
                  "to": "17:00"
                },
                "sunday": {
                  "active": true,
                  "from": "9:00",
                  "to": "17:00"
                }
              },
              "bandwidth": {
                "settings": "custom",
                "bandwidthLimits": {
                  "limitUp": 1000000,
                  "limitDown": 1000000
                }
              },
              "firewallAndTrafficShaping": {
                "settings": "custom",
                "trafficShapingRules": [
                  {
                    "definitions": [
                      {
                        "type": "host",
                        "value": "google.com"
                      }
                    ],
                    "perClientBandwidthLimits": {
                      "settings": "custom",
                      "bandwidthLimits": {
                        "limitUp": 1000000,
                        "limitDown": 1000000
                      }
                    },
                    "dscpTagValue": 0,
                    "pcpTagValue": 0,
                    "priority": "normal"
                  }
                ],
                "l3FirewallRules": [
                  {
                    "comment": "Allow TCP traffic to subnet with HTTP servers.",
                    "policy": "allow",
                    "protocol": "tcp",
                    "destPort": "443",
                    "destCidr": "192.168.1.0/24"
                  }
                ],
                "l7FirewallRules": [
                  {
                    "policy": "deny",
                    "type": "host",
                    "value": "google.com"
                  }
                ]
              },
              "contentFiltering": {
                "allowedUrlPatterns": {
                  "settings": "network default",
                  "patterns": []
                },
                "blockedUrlPatterns": {
                  "settings": "append",
                  "patterns": [
                    "http://www.example.com",
                    "http://www.betting.com"
                  ]
                },
                "blockedUrlCategories": {
                  "settings": "override",
                  "categories": [
                    "meraki:contentFiltering/category/1",
                    "meraki:contentFiltering/category/7"
                  ]
                }
              },
              "splashAuthSettings": "bypass",
              "vlanTagging": {
                "settings": "custom",
                "vlanId": "1"
              },
              "bonjourForwarding": {
                "settings": "custom",
                "rules": [
                  {
                    "description": "A simple bonjour rule",
                    "vlanId": "1",
                    "services": [
                      "All Services"
                    ]
                  }
                ]
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        group_policy_id = urllib.parse.quote(str(group_policy_id), safe="")
        path = f"/networks/{network_id}/groupPolicies/{group_policy_id}"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkGroupPolicy",
            path=path,
            response_schema=GetNetworkGroupPolicyResponse,
        )

    async def update_network_group_policy(
        self,
        *,
        network_id: str,
        group_policy_id: str,
        name: str | None = None,
        scheduling: UpdateNetworkGroupPolicyScheduling | None = None,
        bandwidth: UpdateNetworkGroupPolicyBandwidth | None = None,
        firewall_and_traffic_shaping: UpdateNetworkGroupPolicyFirewallAndTrafficShaping
        | None = None,
        content_filtering: UpdateNetworkGroupPolicyContentFiltering | None = None,
        splash_auth_settings: UpdateNetworkGroupPolicySplashAuthSettings | None = None,
        vlan_tagging: UpdateNetworkGroupPolicyVlanTagging | None = None,
        bonjour_forwarding: UpdateNetworkGroupPolicyBonjourForwarding | None = None,
    ) -> UpdateNetworkGroupPolicyResponse:
        """Update a group policy.

        [API documentation: updateNetworkGroupPolicy](https://developer.cisco.com/meraki/api-v1/#!update-network-group-policy)

        Args:
            network_id: Network ID.
            group_policy_id: Group policy ID.
            name: The name for your group policy.
            scheduling: The schedule for the group policy. Schedules are applied to days of the
                week.
            bandwidth: The bandwidth settings for clients bound to your group policy.
            firewall_and_traffic_shaping: The firewall and traffic shaping rules and settings for
                your policy.
            content_filtering: The content filtering settings for your group policy.
            splash_auth_settings: Whether clients bound to your policy will bypass splash
                authorization or behave according to the network's rules. Can be one of
                'network default' or 'bypass'. Only available if your network has a
                wireless configuration.
            vlan_tagging: The VLAN tagging settings for your group policy. Only available if your
                network has a wireless configuration.
            bonjour_forwarding: The Bonjour settings for your group policy. Only valid if your
                network has a wireless configuration.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "groupPolicyId": "101",
              "scheduling": {
                "enabled": true,
                "monday": {
                  "active": true,
                  "from": "9:00",
                  "to": "17:00"
                },
                "tuesday": {
                  "active": true,
                  "from": "9:00",
                  "to": "17:00"
                },
                "wednesday": {
                  "active": true,
                  "from": "9:00",
                  "to": "17:00"
                },
                "thursday": {
                  "active": true,
                  "from": "9:00",
                  "to": "17:00"
                },
                "friday": {
                  "active": true,
                  "from": "9:00",
                  "to": "17:00"
                },
                "saturday": {
                  "active": true,
                  "from": "9:00",
                  "to": "17:00"
                },
                "sunday": {
                  "active": true,
                  "from": "9:00",
                  "to": "17:00"
                }
              },
              "bandwidth": {
                "settings": "custom",
                "bandwidthLimits": {
                  "limitUp": 1000000,
                  "limitDown": 1000000
                }
              },
              "firewallAndTrafficShaping": {
                "settings": "custom",
                "trafficShapingRules": [
                  {
                    "definitions": [
                      {
                        "type": "host",
                        "value": "google.com"
                      }
                    ],
                    "perClientBandwidthLimits": {
                      "settings": "custom",
                      "bandwidthLimits": {
                        "limitUp": 1000000,
                        "limitDown": 1000000
                      }
                    },
                    "dscpTagValue": 0,
                    "pcpTagValue": 0,
                    "priority": "normal"
                  }
                ],
                "l3FirewallRules": [
                  {
                    "comment": "Allow TCP traffic to subnet with HTTP servers.",
                    "policy": "allow",
                    "protocol": "tcp",
                    "destPort": "443",
                    "destCidr": "192.168.1.0/24"
                  }
                ],
                "l7FirewallRules": [
                  {
                    "policy": "deny",
                    "type": "host",
                    "value": "google.com"
                  }
                ]
              },
              "contentFiltering": {
                "allowedUrlPatterns": {
                  "settings": "network default",
                  "patterns": []
                },
                "blockedUrlPatterns": {
                  "settings": "append",
                  "patterns": [
                    "http://www.example.com",
                    "http://www.betting.com"
                  ]
                },
                "blockedUrlCategories": {
                  "settings": "override",
                  "categories": [
                    "meraki:contentFiltering/category/1",
                    "meraki:contentFiltering/category/7"
                  ]
                }
              },
              "splashAuthSettings": "bypass",
              "vlanTagging": {
                "settings": "custom",
                "vlanId": "1"
              },
              "bonjourForwarding": {
                "settings": "custom",
                "rules": [
                  {
                    "description": "A simple bonjour rule",
                    "vlanId": "1",
                    "services": [
                      "All Services"
                    ]
                  }
                ]
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        group_policy_id = urllib.parse.quote(str(group_policy_id), safe="")
        path = f"/networks/{network_id}/groupPolicies/{group_policy_id}"

        payload: dict[str, Any] = {}
        if name is not None:
            payload["name"] = name
        if scheduling is not None:
            payload["scheduling"] = scheduling.model_dump(by_alias=True, exclude_none=True)
        if bandwidth is not None:
            payload["bandwidth"] = bandwidth.model_dump(by_alias=True, exclude_none=True)
        if firewall_and_traffic_shaping is not None:
            payload["firewallAndTrafficShaping"] = firewall_and_traffic_shaping.model_dump(
                by_alias=True, exclude_none=True
            )
        if content_filtering is not None:
            payload["contentFiltering"] = content_filtering.model_dump(
                by_alias=True, exclude_none=True
            )
        if splash_auth_settings is not None:
            payload["splashAuthSettings"] = splash_auth_settings
        if vlan_tagging is not None:
            payload["vlanTagging"] = vlan_tagging.model_dump(by_alias=True, exclude_none=True)
        if bonjour_forwarding is not None:
            payload["bonjourForwarding"] = bonjour_forwarding.model_dump(
                by_alias=True, exclude_none=True
            )

        return await self._session.put(
            scope="networks",
            operation_id="updateNetworkGroupPolicy",
            path=path,
            json=payload,
            response_schema=UpdateNetworkGroupPolicyResponse,
        )

    async def delete_network_group_policy(
        self, *, network_id: str, group_policy_id: str, force: bool | None = None
    ) -> None:
        """Delete a group policy.

        [API documentation: deleteNetworkGroupPolicy](https://developer.cisco.com/meraki/api-v1/#!delete-network-group-policy)

        Args:
            network_id: Network ID.
            group_policy_id: Group policy ID.
            force: If true, the system deletes the GP even if there are active clients using the GP.
                After deletion, active clients that were assigned to that Group Policy
                will be left without any policy applied. Default is false.

        Returns:
            Successful operation.

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        group_policy_id = urllib.parse.quote(str(group_policy_id), safe="")
        path = f"/networks/{network_id}/groupPolicies/{group_policy_id}"

        params: dict[str, Any] = {}
        if force is not None:
            params["force"] = force

        return await self._session.delete(
            scope="networks", operation_id="deleteNetworkGroupPolicy", path=path
        )

    def get_network_health_alerts(
        self, network_id: str
    ) -> AsyncPaginatedResponse[GetNetworkHealthAlertsResponseItem]:
        """Return all global alerts on this network.

        [API documentation: getNetworkHealthAlerts](https://developer.cisco.com/meraki/api-v1/#!get-network-health-alerts)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "id": "1234",
                "category": "Connectivity",
                "type": "Poor connectivity to the Meraki cloud",
                "severity": "info",
                "scope": {
                  "devices": [
                    {
                      "url": "https://n1.meraki.com//n//manage/nodes/new_list/000000000000",
                      "name": "My AP",
                      "productType": "switch",
                      "serial": "Q234-ABCD-5678",
                      "mac": "00:11:22:33:44:55",
                      "lldp": {
                        "portId": "1"
                      },
                      "clients": [
                        {
                          "mac": "22:33:44:55:66:77"
                        }
                      ]
                    }
                  ],
                  "applications": [
                    {
                      "url": "https://n1.meraki.com//n//manage/nodes/list",
                      "name": "Application on application server"
                    }
                  ],
                  "peers": [
                    {
                      "url": "https://n1.meraki.com//n//manage/nodes/list",
                      "network": {
                        "name": "Main Office",
                        "id": "N_24329156"
                      }
                    }
                  ]
                }
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/health/alerts"

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkHealthAlerts",
            path=path,
            item_schema=GetNetworkHealthAlertsResponseItem,
        )

    def get_network_meraki_auth_users(
        self, network_id: str
    ) -> AsyncPaginatedResponse[GetNetworkMerakiAuthUsersResponseItem]:
        """List the authorized users configured under Meraki Authentication for a network (splash guest or RADIUS users for a wireless network, or client VPN users for a MX network).

        [API documentation: getNetworkMerakiAuthUsers](https://developer.cisco.com/meraki/api-v1/#!get-network-meraki-auth-users)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "id": "aGlAaGkuY29t",
                "email": "miles@meraki.com",
                "name": "Miles Meraki",
                "createdAt": "2018-02-11T00:00:00.090210Z",
                "accountType": "802.1X",
                "isAdmin": false,
                "authorizations": [
                  {
                    "ssidNumber": 1,
                    "authorizedZone": "Store WiFi",
                    "expiresAt": "2018-03-13T00:00:00.090210Z",
                    "authorizedByName": "Miles Meraki",
                    "authorizedByEmail": "miles@meraki.com"
                  }
                ]
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/merakiAuthUsers"

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkMerakiAuthUsers",
            path=path,
            item_schema=GetNetworkMerakiAuthUsersResponseItem,
        )

    async def create_network_meraki_auth_user(
        self,
        *,
        network_id: str,
        email: str,
        authorizations: list[CreateNetworkMerakiAuthUserAuthorizationsItem],
        name: str | None = None,
        password: str | None = None,
        account_type: CreateNetworkMerakiAuthUserAccountType | None = None,
        email_password_to_user: bool | None = None,
        is_admin: bool | None = None,
    ) -> CreateNetworkMerakiAuthUserResponse:
        """Authorize a user configured with Meraki Authentication for a network (currently supports 802.1X, splash guest, and client VPN users, and currently, organizations have a 50,000 user cap).

        [API documentation: createNetworkMerakiAuthUser](https://developer.cisco.com/meraki/api-v1/#!create-network-meraki-auth-user)

        Args:
            network_id: Network ID.
            email: Email address of the user.
            name: Name of the user. Only required If the user is not a Dashboard administrator.
            password: The password for this user account. Only required If the user is not a
                Dashboard administrator.
            account_type: Authorization type for user. Can be 'Guest' or '802.1X' for wireless
                networks, or 'Client VPN' for MX networks. Defaults to '802.1X'.
            email_password_to_user: Whether or not Meraki should email the password to user. Default
                is false.
            is_admin: Whether or not the user is a Dashboard administrator.
            authorizations: Authorization zones and expiration dates for the user.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "id": "aGlAaGkuY29t",
              "email": "miles@meraki.com",
              "name": "Miles Meraki",
              "createdAt": "2018-02-11T00:00:00.090210Z",
              "accountType": "802.1X",
              "isAdmin": false,
              "authorizations": [
                {
                  "ssidNumber": 1,
                  "authorizedZone": "Store WiFi",
                  "expiresAt": "2018-03-13T00:00:00.090210Z",
                  "authorizedByName": "Miles Meraki",
                  "authorizedByEmail": "miles@meraki.com"
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/merakiAuthUsers"

        payload: dict[str, Any] = {}
        if email is not None:
            payload["email"] = email
        if name is not None:
            payload["name"] = name
        if password is not None:
            payload["password"] = password
        if account_type is not None:
            payload["accountType"] = account_type
        if email_password_to_user is not None:
            payload["emailPasswordToUser"] = email_password_to_user
        if is_admin is not None:
            payload["isAdmin"] = is_admin
        if authorizations is not None:
            payload["authorizations"] = [
                item.model_dump(by_alias=True, exclude_none=True) for item in authorizations
            ]

        return await self._session.post(
            scope="networks",
            operation_id="createNetworkMerakiAuthUser",
            path=path,
            json=payload,
            response_schema=CreateNetworkMerakiAuthUserResponse,
        )

    async def get_network_meraki_auth_user(
        self, *, network_id: str, meraki_auth_user_id: str
    ) -> GetNetworkMerakiAuthUserResponse:
        """Return the Meraki Auth splash guest, RADIUS, or client VPN user.

        [API documentation: getNetworkMerakiAuthUser](https://developer.cisco.com/meraki/api-v1/#!get-network-meraki-auth-user)

        Args:
            network_id: Network ID.
            meraki_auth_user_id: Meraki auth user ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "id": "aGlAaGkuY29t",
              "email": "miles@meraki.com",
              "name": "Miles Meraki",
              "createdAt": "2018-02-11T00:00:00.090210Z",
              "accountType": "802.1X",
              "isAdmin": false,
              "authorizations": [
                {
                  "ssidNumber": 1,
                  "authorizedZone": "Store WiFi",
                  "expiresAt": "2018-03-13T00:00:00.090210Z",
                  "authorizedByName": "Miles Meraki",
                  "authorizedByEmail": "miles@meraki.com"
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        meraki_auth_user_id = urllib.parse.quote(str(meraki_auth_user_id), safe="")
        path = f"/networks/{network_id}/merakiAuthUsers/{meraki_auth_user_id}"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkMerakiAuthUser",
            path=path,
            response_schema=GetNetworkMerakiAuthUserResponse,
        )

    async def update_network_meraki_auth_user(
        self,
        *,
        network_id: str,
        meraki_auth_user_id: str,
        name: str | None = None,
        password: str | None = None,
        email_password_to_user: bool | None = None,
        authorizations: list[UpdateNetworkMerakiAuthUserAuthorizationsItem] | None = None,
    ) -> UpdateNetworkMerakiAuthUserResponse:
        """Update a user configured with Meraki Authentication (currently, 802.1X RADIUS, splash guest, and client VPN users can be updated).

        [API documentation: updateNetworkMerakiAuthUser](https://developer.cisco.com/meraki/api-v1/#!update-network-meraki-auth-user)

        Args:
            network_id: Network ID.
            meraki_auth_user_id: Meraki auth user ID.
            name: Name of the user. Only allowed If the user is not Dashboard administrator.
            password: The password for this user account. Only allowed If the user is not Dashboard
                administrator.
            email_password_to_user: Whether or not Meraki should email the password to user. Default
                is false.
            authorizations: Authorization zones and expiration dates for the user.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "id": "aGlAaGkuY29t",
              "email": "miles@meraki.com",
              "name": "Miles Meraki",
              "createdAt": "2018-02-11T00:00:00.090210Z",
              "accountType": "802.1X",
              "isAdmin": false,
              "authorizations": [
                {
                  "ssidNumber": 1,
                  "authorizedZone": "Store WiFi",
                  "expiresAt": "2018-03-13T00:00:00.090210Z",
                  "authorizedByName": "Miles Meraki",
                  "authorizedByEmail": "miles@meraki.com"
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        meraki_auth_user_id = urllib.parse.quote(str(meraki_auth_user_id), safe="")
        path = f"/networks/{network_id}/merakiAuthUsers/{meraki_auth_user_id}"

        payload: dict[str, Any] = {}
        if name is not None:
            payload["name"] = name
        if password is not None:
            payload["password"] = password
        if email_password_to_user is not None:
            payload["emailPasswordToUser"] = email_password_to_user
        if authorizations is not None:
            payload["authorizations"] = [
                item.model_dump(by_alias=True, exclude_none=True) for item in authorizations
            ]

        return await self._session.put(
            scope="networks",
            operation_id="updateNetworkMerakiAuthUser",
            path=path,
            json=payload,
            response_schema=UpdateNetworkMerakiAuthUserResponse,
        )

    async def delete_network_meraki_auth_user(
        self, *, network_id: str, meraki_auth_user_id: str, delete: bool | None = None
    ) -> None:
        """Delete an 802.1X RADIUS user, or deauthorize and optionally delete a splash guest or client VPN user.

        [API documentation: deleteNetworkMerakiAuthUser](https://developer.cisco.com/meraki/api-v1/#!delete-network-meraki-auth-user)

        Args:
            network_id: Network ID.
            meraki_auth_user_id: Meraki auth user ID.
            delete: If the ID supplied is for a splash guest or client VPN user, and that user is
                not authorized for any other networks in the organization, then also
                delete the user. 802.1X RADIUS users are always deleted regardless of
                this optional attribute.

        Returns:
            Successful operation.

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        meraki_auth_user_id = urllib.parse.quote(str(meraki_auth_user_id), safe="")
        path = f"/networks/{network_id}/merakiAuthUsers/{meraki_auth_user_id}"

        params: dict[str, Any] = {}
        if delete is not None:
            params["delete"] = delete

        return await self._session.delete(
            scope="networks", operation_id="deleteNetworkMerakiAuthUser", path=path
        )

    def get_network_mqtt_brokers(
        self, network_id: str
    ) -> AsyncPaginatedResponse[GetNetworkMqttBrokersResponseItem]:
        """List the MQTT brokers for this network.

        [API documentation: getNetworkMqttBrokers](https://developer.cisco.com/meraki/api-v1/#!get-network-mqtt-brokers)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "id": "1234",
                "name": "MQTT_Broker_1",
                "host": "1.2.3.4",
                "port": 443,
                "security": {
                  "mode": "tls",
                  "tls": {
                    "hasCaCertificate": true,
                    "verifyHostnames": true
                  }
                },
                "authentication": {
                  "username": "milesmeraki"
                }
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/mqttBrokers"

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkMqttBrokers",
            path=path,
            item_schema=GetNetworkMqttBrokersResponseItem,
        )

    async def create_network_mqtt_broker(
        self,
        *,
        network_id: str,
        name: str,
        host: str,
        port: int,
        security: CreateNetworkMqttBrokerSecurity | None = None,
        authentication: CreateNetworkMqttBrokerAuthentication | None = None,
    ) -> CreateNetworkMqttBrokerResponse:
        """Add an MQTT broker.

        [API documentation: createNetworkMqttBroker](https://developer.cisco.com/meraki/api-v1/#!create-network-mqtt-broker)

        Args:
            network_id: Network ID.
            name: Name of the MQTT broker.
            host: Host name/IP address where the MQTT broker runs.
            port: Host port though which the MQTT broker can be reached.
            security: Security settings of the MQTT broker.
            authentication: Authentication settings of the MQTT broker.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "id": "1234",
              "name": "MQTT_Broker_1",
              "host": "1.2.3.4",
              "port": 443,
              "security": {
                "mode": "tls",
                "tls": {
                  "hasCaCertificate": true,
                  "verifyHostnames": true
                }
              },
              "authentication": {
                "username": "milesmeraki"
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/mqttBrokers"

        payload: dict[str, Any] = {}
        if name is not None:
            payload["name"] = name
        if host is not None:
            payload["host"] = host
        if port is not None:
            payload["port"] = port
        if security is not None:
            payload["security"] = security.model_dump(by_alias=True, exclude_none=True)
        if authentication is not None:
            payload["authentication"] = authentication.model_dump(by_alias=True, exclude_none=True)

        return await self._session.post(
            scope="networks",
            operation_id="createNetworkMqttBroker",
            path=path,
            json=payload,
            response_schema=CreateNetworkMqttBrokerResponse,
        )

    async def get_network_mqtt_broker(
        self, *, network_id: str, mqtt_broker_id: str
    ) -> GetNetworkMqttBrokerResponse:
        """Return an MQTT broker.

        [API documentation: getNetworkMqttBroker](https://developer.cisco.com/meraki/api-v1/#!get-network-mqtt-broker)

        Args:
            network_id: Network ID.
            mqtt_broker_id: Mqtt broker ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "id": "1234",
              "name": "MQTT_Broker_1",
              "host": "1.2.3.4",
              "port": 443,
              "security": {
                "mode": "tls",
                "tls": {
                  "hasCaCertificate": true,
                  "verifyHostnames": true
                }
              },
              "authentication": {
                "username": "milesmeraki"
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        mqtt_broker_id = urllib.parse.quote(str(mqtt_broker_id), safe="")
        path = f"/networks/{network_id}/mqttBrokers/{mqtt_broker_id}"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkMqttBroker",
            path=path,
            response_schema=GetNetworkMqttBrokerResponse,
        )

    async def update_network_mqtt_broker(
        self,
        *,
        network_id: str,
        mqtt_broker_id: str,
        name: str | None = None,
        host: str | None = None,
        port: int | None = None,
        security: UpdateNetworkMqttBrokerSecurity | None = None,
        authentication: UpdateNetworkMqttBrokerAuthentication | None = None,
    ) -> UpdateNetworkMqttBrokerResponse:
        """Update an MQTT broker.

        [API documentation: updateNetworkMqttBroker](https://developer.cisco.com/meraki/api-v1/#!update-network-mqtt-broker)

        Args:
            network_id: Network ID.
            mqtt_broker_id: Mqtt broker ID.
            name: Name of the MQTT broker.
            host: Host name/IP address where the MQTT broker runs.
            port: Host port though which the MQTT broker can be reached.
            security: Security settings of the MQTT broker.
            authentication: Authentication settings of the MQTT broker.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "id": "1234",
              "name": "MQTT_Broker_1",
              "host": "1.2.3.4",
              "port": 443,
              "security": {
                "mode": "tls",
                "tls": {
                  "hasCaCertificate": true,
                  "verifyHostnames": true
                }
              },
              "authentication": {
                "username": "milesmeraki"
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        mqtt_broker_id = urllib.parse.quote(str(mqtt_broker_id), safe="")
        path = f"/networks/{network_id}/mqttBrokers/{mqtt_broker_id}"

        payload: dict[str, Any] = {}
        if name is not None:
            payload["name"] = name
        if host is not None:
            payload["host"] = host
        if port is not None:
            payload["port"] = port
        if security is not None:
            payload["security"] = security.model_dump(by_alias=True, exclude_none=True)
        if authentication is not None:
            payload["authentication"] = authentication.model_dump(by_alias=True, exclude_none=True)

        return await self._session.put(
            scope="networks",
            operation_id="updateNetworkMqttBroker",
            path=path,
            json=payload,
            response_schema=UpdateNetworkMqttBrokerResponse,
        )

    async def delete_network_mqtt_broker(self, *, network_id: str, mqtt_broker_id: str) -> None:
        """Delete an MQTT broker.

        [API documentation: deleteNetworkMqttBroker](https://developer.cisco.com/meraki/api-v1/#!delete-network-mqtt-broker)

        Args:
            network_id: Network ID.
            mqtt_broker_id: Mqtt broker ID.

        Returns:
            Successful operation.

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        mqtt_broker_id = urllib.parse.quote(str(mqtt_broker_id), safe="")
        path = f"/networks/{network_id}/mqttBrokers/{mqtt_broker_id}"

        return await self._session.delete(
            scope="networks", operation_id="deleteNetworkMqttBroker", path=path
        )

    async def get_network_netflow(self, network_id: str) -> GetNetworkNetflowResponse:
        """Return the NetFlow traffic reporting settings for a network.

        [API documentation: getNetworkNetflow](https://developer.cisco.com/meraki/api-v1/#!get-network-netflow)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "reportingEnabled": true,
              "collectorIp": "1.2.3.4",
              "collectorPort": 443,
              "etaEnabled": true,
              "etaDstPort": 443
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/netflow"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkNetflow",
            path=path,
            response_schema=GetNetworkNetflowResponse,
        )

    async def update_network_netflow(
        self,
        network_id: str,
        *,
        reporting_enabled: bool | None = None,
        collector_ip: str | None = None,
        collector_port: int | None = None,
        eta_enabled: bool | None = None,
        eta_dst_port: int | None = None,
    ) -> UpdateNetworkNetflowResponse:
        """Update the NetFlow traffic reporting settings for a network.

        [API documentation: updateNetworkNetflow](https://developer.cisco.com/meraki/api-v1/#!update-network-netflow)

        Args:
            network_id: Network ID.
            reporting_enabled: Boolean indicating whether NetFlow traffic reporting is enabled
                (true) or disabled (false).
            collector_ip: The IPv4 address of the NetFlow collector.
            collector_port: The port that the NetFlow collector will be listening on.
            eta_enabled: Boolean indicating whether Encrypted Traffic Analytics is enabled (true) or
                disabled (false).
            eta_dst_port: The port that the Encrypted Traffic Analytics collector will be listening
                on.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "reportingEnabled": true,
              "collectorIp": "1.2.3.4",
              "collectorPort": 443,
              "etaEnabled": true,
              "etaDstPort": 443
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/netflow"

        payload: dict[str, Any] = {}
        if reporting_enabled is not None:
            payload["reportingEnabled"] = reporting_enabled
        if collector_ip is not None:
            payload["collectorIp"] = collector_ip
        if collector_port is not None:
            payload["collectorPort"] = collector_port
        if eta_enabled is not None:
            payload["etaEnabled"] = eta_enabled
        if eta_dst_port is not None:
            payload["etaDstPort"] = eta_dst_port

        return await self._session.put(
            scope="networks",
            operation_id="updateNetworkNetflow",
            path=path,
            json=payload,
            response_schema=UpdateNetworkNetflowResponse,
        )

    def get_network_network_health_channel_utilization(
        self,
        network_id: str,
        *,
        t0: str | None = None,
        t1: str | None = None,
        timespan: float | None = None,
        resolution: int | None = None,
        per_page: int | None = None,
        starting_after: str | None = None,
        ending_before: str | None = None,
        total_pages: int | Literal["all"] = "all",
        direction: Literal["prev", "next"] = "next",
    ) -> AsyncPaginatedResponse[GetNetworkNetworkHealthChannelUtilizationResponseItem]:
        """Get the channel utilization over each radio for all APs in a network.

        [API documentation: getNetworkNetworkHealthChannelUtilization](https://developer.cisco.com/meraki/api-v1/#!get-network-network-health-channel-utilization)

        Args:
            network_id: Network ID.
            t0: The beginning of the timespan for the data. The maximum lookback period is 31 days
                from today.
            t1: The end of the timespan for the data. t1 can be a maximum of 31 days after t0.
            timespan: The timespan for which the information will be fetched. If specifying
                timespan, do not specify parameters t0 and t1. The value must be in
                seconds and be less than or equal to 31 days. The default is 1 day.
            resolution: The time resolution in seconds for returned data. The valid resolutions are:
                600. The default is 600.
            per_page: The number of entries per page returned. Acceptable range is 3 - 100. Default
                is 10.
            starting_after: A token used by the server to indicate the start of the page. Often this
                is a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            ending_before: A token used by the server to indicate the end of the page. Often this is
                a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            total_pages: use with per_page to get total results up to total_pages * per_page; -1 or
                "all" for all pages.
            direction: direction to paginate, either "next" (default) or "prev" page.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "serial": "Q234-ABCD-5678",
                "model": "MR34",
                "tags": " recently-added ",
                "wifi0": [
                  {
                    "startTime": "2018-10-09T22:18:27Z",
                    "endTime": "2018-10-09T22:19:27Z",
                    "utilizationTotal": 33.84,
                    "utilization80211": 32.0,
                    "utilizationNon80211": 1.84
                  }
                ],
                "wifi1": [
                  {
                    "startTime": "2018-10-09T22:18:27Z",
                    "endTime": "2018-10-09T22:19:27Z",
                    "utilizationTotal": 33.84,
                    "utilization80211": 32.0,
                    "utilizationNon80211": 1.84
                  }
                ]
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/networkHealth/channelUtilization"

        params: dict[str, Any] = {}
        if t0 is not None:
            params["t0"] = t0
        if t1 is not None:
            params["t1"] = t1
        if timespan is not None:
            params["timespan"] = timespan
        if resolution is not None:
            params["resolution"] = resolution
        if per_page is not None:
            params["perPage"] = per_page
        if starting_after is not None:
            params["startingAfter"] = starting_after
        if ending_before is not None:
            params["endingBefore"] = ending_before

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkNetworkHealthChannelUtilization",
            path=path,
            params=params,
            total_pages=total_pages,
            direction=direction,
            item_schema=GetNetworkNetworkHealthChannelUtilizationResponseItem,
        )

    async def get_network_pii_pii_keys(
        self,
        network_id: str,
        *,
        username: str | None = None,
        email: str | None = None,
        mac: str | None = None,
        serial: str | None = None,
        imei: str | None = None,
        bluetooth_mac: str | None = None,
    ) -> GetNetworkPiiPiiKeysResponse:
        """List the keys required to access Personally Identifiable Information (PII) for a given identifier.

        [API documentation: getNetworkPiiPiiKeys](https://developer.cisco.com/meraki/api-v1/#!get-network-pii-pii-keys)

        Args:
            network_id: Network ID.
            username: The username of a Systems Manager user.
            email: The email of a network user account or a Systems Manager device.
            mac: The MAC of a network client device or a Systems Manager device.
            serial: The serial of a Systems Manager device.
            imei: The IMEI of a Systems Manager device.
            bluetooth_mac: The MAC of a Bluetooth client.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "N_1234": {
                "macs": [
                  "00:77:00:77:00:77"
                ],
                "emails": [
                  "fake@example.com"
                ],
                "usernames": [
                  "fakename"
                ],
                "serials": [
                  "Q234-ABCD-0001"
                ],
                "imeis": [
                  "990000862471854"
                ],
                "bluetoothMacs": [
                  "00:77:00:77:00:77"
                ]
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/pii/piiKeys"

        params: dict[str, Any] = {}
        if username is not None:
            params["username"] = username
        if email is not None:
            params["email"] = email
        if mac is not None:
            params["mac"] = mac
        if serial is not None:
            params["serial"] = serial
        if imei is not None:
            params["imei"] = imei
        if bluetooth_mac is not None:
            params["bluetoothMac"] = bluetooth_mac

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkPiiPiiKeys",
            path=path,
            params=params,
            response_schema=GetNetworkPiiPiiKeysResponse,
        )

    def get_network_pii_requests(
        self, network_id: str
    ) -> AsyncPaginatedResponse[GetNetworkPiiRequestsResponseItem]:
        """List the PII requests for this network or organization.

        [API documentation: getNetworkPiiRequests](https://developer.cisco.com/meraki/api-v1/#!get-network-pii-requests)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "id": "1234",
                "organizationWide": false,
                "networkId": "N_1234",
                "type": "delete",
                "mac": "00:77:00:77:00:77",
                "datasets": "['usage', 'events']",
                "status": "Completed",
                "createdAt": 1524692227,
                "completedAt": 1524702227
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/pii/requests"

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkPiiRequests",
            path=path,
            item_schema=GetNetworkPiiRequestsResponseItem,
        )

    async def create_network_pii_request(
        self,
        network_id: str,
        *,
        type_: CreateNetworkPiiRequestType | None = None,
        datasets: list[str] | None = None,
        username: str | None = None,
        email: str | None = None,
        mac: str | None = None,
        sm_device_id: str | None = None,
        sm_user_id: str | None = None,
    ) -> CreateNetworkPiiRequestResponse:
        """Submit a new delete or restrict processing PII request.

        [API documentation: createNetworkPiiRequest](https://developer.cisco.com/meraki/api-v1/#!create-network-pii-request)

        Args:
            network_id: Network ID.
            type_: One of "delete" or "restrict processing".
            datasets: The datasets related to the provided key that should be deleted. Only applies
                to "delete" requests. The value "all" will be expanded to all datasets
                applicable to this type. The datasets by applicable to each type are:
                mac (usage, events, traffic), email (users, loginAttempts), username
                (users, loginAttempts), bluetoothMac (client, connectivity), smDeviceId
                (device), smUserId (user).
            username: The username of a network log in. Only applies to "delete" requests.
            email: The email of a network user account. Only applies to "delete" requests.
            mac: The MAC of a network client device. Applies to both "restrict processing" and
                "delete" requests.
            sm_device_id: The sm_device_id of a Systems Manager device. The only way to "restrict
                processing" or "delete" a Systems Manager device. Must include "device"
                in the dataset for a "delete" request to destroy the device.
            sm_user_id: The sm_user_id of a Systems Manager user. The only way to "restrict
                processing" or "delete" a Systems Manager user. Must include "user" in
                the dataset for a "delete" request to destroy the user.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "id": "1234",
              "organizationWide": false,
              "networkId": "N_1234",
              "type": "delete",
              "mac": "00:77:00:77:00:77",
              "datasets": "['usage', 'events']",
              "status": "Completed",
              "createdAt": 1524692227,
              "completedAt": 1524702227
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/pii/requests"

        payload: dict[str, Any] = {}
        if type_ is not None:
            payload["type"] = type_
        if datasets is not None:
            payload["datasets"] = datasets
        if username is not None:
            payload["username"] = username
        if email is not None:
            payload["email"] = email
        if mac is not None:
            payload["mac"] = mac
        if sm_device_id is not None:
            payload["smDeviceId"] = sm_device_id
        if sm_user_id is not None:
            payload["smUserId"] = sm_user_id

        return await self._session.post(
            scope="networks",
            operation_id="createNetworkPiiRequest",
            path=path,
            json=payload,
            response_schema=CreateNetworkPiiRequestResponse,
        )

    async def get_network_pii_request(
        self, *, network_id: str, request_id: str
    ) -> GetNetworkPiiRequestResponse:
        """Return a PII request.

        [API documentation: getNetworkPiiRequest](https://developer.cisco.com/meraki/api-v1/#!get-network-pii-request)

        Args:
            network_id: Network ID.
            request_id: Request ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "id": "1234",
              "organizationWide": false,
              "networkId": "N_1234",
              "type": "delete",
              "mac": "00:77:00:77:00:77",
              "datasets": "['usage', 'events']",
              "status": "Completed",
              "createdAt": 1524692227,
              "completedAt": 1524702227
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        request_id = urllib.parse.quote(str(request_id), safe="")
        path = f"/networks/{network_id}/pii/requests/{request_id}"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkPiiRequest",
            path=path,
            response_schema=GetNetworkPiiRequestResponse,
        )

    async def delete_network_pii_request(self, *, network_id: str, request_id: str) -> None:
        """Delete a restrict processing PII request.

        [API documentation: deleteNetworkPiiRequest](https://developer.cisco.com/meraki/api-v1/#!delete-network-pii-request)

        Args:
            network_id: Network ID.
            request_id: Request ID.

        Returns:
            Successful operation.

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        request_id = urllib.parse.quote(str(request_id), safe="")
        path = f"/networks/{network_id}/pii/requests/{request_id}"

        return await self._session.delete(
            scope="networks", operation_id="deleteNetworkPiiRequest", path=path
        )

    async def get_network_pii_sm_devices_for_key(
        self,
        network_id: str,
        *,
        username: str | None = None,
        email: str | None = None,
        mac: str | None = None,
        serial: str | None = None,
        imei: str | None = None,
        bluetooth_mac: str | None = None,
    ) -> GetNetworkPiiSmDevicesForKeyResponse:
        """Given a piece of Personally Identifiable Information (PII), return the Systems Manager device ID(s) associated with that identifier.

        [API documentation: getNetworkPiiSmDevicesForKey](https://developer.cisco.com/meraki/api-v1/#!get-network-pii-sm-devices-for-key)

        Args:
            network_id: Network ID.
            username: The username of a Systems Manager user.
            email: The email of a network user account or a Systems Manager device.
            mac: The MAC of a network client device or a Systems Manager device.
            serial: The serial of a Systems Manager device.
            imei: The IMEI of a Systems Manager device.
            bluetooth_mac: The MAC of a Bluetooth client.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "N_1234": [
                "1099541095293"
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/pii/smDevicesForKey"

        params: dict[str, Any] = {}
        if username is not None:
            params["username"] = username
        if email is not None:
            params["email"] = email
        if mac is not None:
            params["mac"] = mac
        if serial is not None:
            params["serial"] = serial
        if imei is not None:
            params["imei"] = imei
        if bluetooth_mac is not None:
            params["bluetoothMac"] = bluetooth_mac

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkPiiSmDevicesForKey",
            path=path,
            params=params,
            response_schema=GetNetworkPiiSmDevicesForKeyResponse,
        )

    async def get_network_pii_sm_owners_for_key(
        self,
        network_id: str,
        *,
        username: str | None = None,
        email: str | None = None,
        mac: str | None = None,
        serial: str | None = None,
        imei: str | None = None,
        bluetooth_mac: str | None = None,
    ) -> GetNetworkPiiSmOwnersForKeyResponse:
        """Given a piece of Personally Identifiable Information (PII), return the Systems Manager owner ID(s) associated with that identifier.

        [API documentation: getNetworkPiiSmOwnersForKey](https://developer.cisco.com/meraki/api-v1/#!get-network-pii-sm-owners-for-key)

        Args:
            network_id: Network ID.
            username: The username of a Systems Manager user.
            email: The email of a network user account or a Systems Manager device.
            mac: The MAC of a network client device or a Systems Manager device.
            serial: The serial of a Systems Manager device.
            imei: The IMEI of a Systems Manager device.
            bluetooth_mac: The MAC of a Bluetooth client.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "N_1234": [
                "1099541095293"
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/pii/smOwnersForKey"

        params: dict[str, Any] = {}
        if username is not None:
            params["username"] = username
        if email is not None:
            params["email"] = email
        if mac is not None:
            params["mac"] = mac
        if serial is not None:
            params["serial"] = serial
        if imei is not None:
            params["imei"] = imei
        if bluetooth_mac is not None:
            params["bluetoothMac"] = bluetooth_mac

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkPiiSmOwnersForKey",
            path=path,
            params=params,
            response_schema=GetNetworkPiiSmOwnersForKeyResponse,
        )

    def get_network_policies_by_client(
        self,
        network_id: str,
        *,
        per_page: int | None = None,
        starting_after: str | None = None,
        ending_before: str | None = None,
        t0: str | None = None,
        timespan: float | None = None,
        total_pages: int | Literal["all"] = "all",
        direction: Literal["prev", "next"] = "next",
    ) -> AsyncPaginatedResponse[GetNetworkPoliciesByClientResponseItem]:
        """Get policies for all clients with policies.

        [API documentation: getNetworkPoliciesByClient](https://developer.cisco.com/meraki/api-v1/#!get-network-policies-by-client)

        Args:
            network_id: Network ID.
            per_page: The number of entries per page returned. Acceptable range is 3 - 1000. Default
                is 50.
            starting_after: A token used by the server to indicate the start of the page. Often this
                is a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            ending_before: A token used by the server to indicate the end of the page. Often this is
                a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            t0: The beginning of the timespan for the data. The maximum lookback period is 31 days
                from today.
            timespan: The timespan for which the information will be fetched. If specifying
                timespan, do not specify parameter t0. The value must be in seconds and
                be less than or equal to 31 days. The default is 1 day.
            total_pages: use with per_page to get total results up to total_pages * per_page; -1 or
                "all" for all pages.
            direction: direction to paginate, either "next" (default) or "prev" page.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "name": "my phone",
                "clientId": "abc",
                "assigned": [
                  {
                    "name": "Allowed",
                    "type": "ssid",
                    "groupPolicyId": "100",
                    "ssid": [
                      {
                        "ssidNumber": 1
                      }
                    ]
                  }
                ]
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/policies/byClient"

        params: dict[str, Any] = {}
        if per_page is not None:
            params["perPage"] = per_page
        if starting_after is not None:
            params["startingAfter"] = starting_after
        if ending_before is not None:
            params["endingBefore"] = ending_before
        if t0 is not None:
            params["t0"] = t0
        if timespan is not None:
            params["timespan"] = timespan

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkPoliciesByClient",
            path=path,
            params=params,
            total_pages=total_pages,
            direction=direction,
            item_schema=GetNetworkPoliciesByClientResponseItem,
        )

    async def get_network_settings(self, network_id: str) -> GetNetworkSettingsResponse:
        """Return the settings for a network.

        [API documentation: getNetworkSettings](https://developer.cisco.com/meraki/api-v1/#!get-network-settings)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "localStatusPageEnabled": true,
              "remoteStatusPageEnabled": true,
              "localStatusPage": {
                "authentication": {
                  "enabled": false,
                  "username": "admin"
                }
              },
              "securePort": {
                "enabled": false
              },
              "fips": {
                "enabled": true
              },
              "namedVlans": {
                "enabled": true
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/settings"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkSettings",
            path=path,
            response_schema=GetNetworkSettingsResponse,
        )

    async def update_network_settings(
        self,
        network_id: str,
        *,
        local_status_page_enabled: bool | None = None,
        remote_status_page_enabled: bool | None = None,
        local_status_page: UpdateNetworkSettingsLocalStatusPage | None = None,
        secure_port: UpdateNetworkSettingsSecurePort | None = None,
        named_vlans: UpdateNetworkSettingsNamedVlans | None = None,
    ) -> UpdateNetworkSettingsResponse:
        """Update the settings for a network.

        [API documentation: updateNetworkSettings](https://developer.cisco.com/meraki/api-v1/#!update-network-settings)

        Args:
            network_id: Network ID.
            local_status_page_enabled: Enables / disables the local device status pages (<a
                target='_blank' href='http://my.meraki.com/'>my.meraki.com, </a><a
                target='_blank' href='http://ap.meraki.com/'>ap.meraki.com, </a><a
                target='_blank' href='http://switch.meraki.com/'>switch.meraki.com,
                </a><a target='_blank'
                href='http://wired.meraki.com/'>wired.meraki.com</a>). Optional
                (defaults to false).
            remote_status_page_enabled: Enables / disables access to the device status page (<a
                target='_blank'>http://[device's LAN IP])</a>. Optional. Can only be set
                if localStatusPageEnabled is set to true.
            local_status_page: A hash of Local Status page(s)' authentication options applied to the
                Network.
            secure_port: A hash of SecureConnect options applied to the Network.
            named_vlans: A hash of Named VLANs options applied to the Network.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "localStatusPageEnabled": true,
              "remoteStatusPageEnabled": true,
              "localStatusPage": {
                "authentication": {
                  "enabled": false,
                  "username": "admin"
                }
              },
              "securePort": {
                "enabled": false
              },
              "fips": {
                "enabled": true
              },
              "namedVlans": {
                "enabled": true
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/settings"

        payload: dict[str, Any] = {}
        if local_status_page_enabled is not None:
            payload["localStatusPageEnabled"] = local_status_page_enabled
        if remote_status_page_enabled is not None:
            payload["remoteStatusPageEnabled"] = remote_status_page_enabled
        if local_status_page is not None:
            payload["localStatusPage"] = local_status_page.model_dump(
                by_alias=True, exclude_none=True
            )
        if secure_port is not None:
            payload["securePort"] = secure_port.model_dump(by_alias=True, exclude_none=True)
        if named_vlans is not None:
            payload["namedVlans"] = named_vlans.model_dump(by_alias=True, exclude_none=True)

        return await self._session.put(
            scope="networks",
            operation_id="updateNetworkSettings",
            path=path,
            json=payload,
            response_schema=UpdateNetworkSettingsResponse,
        )

    async def get_network_snmp(self, network_id: str) -> GetNetworkSnmpResponse:
        """Return the SNMP settings for a network.

        [API documentation: getNetworkSnmp](https://developer.cisco.com/meraki/api-v1/#!get-network-snmp)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "access": "users",
              "communityString": "sample",
              "users": [
                {
                  "username": "AzureDiamond",
                  "passphrase": "hunter2"
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/snmp"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkSnmp",
            path=path,
            response_schema=GetNetworkSnmpResponse,
        )

    async def update_network_snmp(
        self,
        network_id: str,
        *,
        access: UpdateNetworkSnmpAccess | None = None,
        community_string: str | None = None,
        users: list[UpdateNetworkSnmpUsersItem] | None = None,
    ) -> UpdateNetworkSnmpResponse:
        """Update the SNMP settings for a network.

        [API documentation: updateNetworkSnmp](https://developer.cisco.com/meraki/api-v1/#!update-network-snmp)

        Args:
            network_id: Network ID.
            access: The type of SNMP access. Can be one of 'none' (disabled), 'community' (V1/V2c),
                or 'users' (V3).
            community_string: The SNMP community string. Only relevant if 'access' is set to
                'community'.
            users: The list of SNMP users. Only relevant if 'access' is set to 'users'.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "access": "users",
              "communityString": "sample",
              "users": [
                {
                  "username": "AzureDiamond",
                  "passphrase": "hunter2"
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/snmp"

        payload: dict[str, Any] = {}
        if access is not None:
            payload["access"] = access
        if community_string is not None:
            payload["communityString"] = community_string
        if users is not None:
            payload["users"] = [item.model_dump(by_alias=True, exclude_none=True) for item in users]

        return await self._session.put(
            scope="networks",
            operation_id="updateNetworkSnmp",
            path=path,
            json=payload,
            response_schema=UpdateNetworkSnmpResponse,
        )

    def get_network_splash_login_attempts(
        self,
        network_id: str,
        *,
        ssid_number: GetNetworkSplashLoginAttemptsSsidNumber | None = None,
        login_identifier: str | None = None,
        timespan: int | None = None,
    ) -> AsyncPaginatedResponse[GetNetworkSplashLoginAttemptsResponseItem]:
        """List the splash login attempts for a network.

        [API documentation: getNetworkSplashLoginAttempts](https://developer.cisco.com/meraki/api-v1/#!get-network-splash-login-attempts)

        Args:
            network_id: Network ID.
            ssid_number: Only return the login attempts for the specified SSID.
            login_identifier: The username, email, or phone number used during login.
            timespan: The timespan, in seconds, for the login attempts. The period will be from
                [timespan] seconds ago until now. The maximum timespan is 3 months.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "name": "Miles Meraki",
                "login": "miles@meraki.com",
                "ssid": "My SSID",
                "loginAt": "2018-02-11T00:00:00.090210Z",
                "gatewayDeviceMac": "00:11:22:33:44:55",
                "clientMac": "22:33:44:55:66:77",
                "clientId": "k74272e",
                "authorization": "success"
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/splashLoginAttempts"

        params: dict[str, Any] = {}
        if ssid_number is not None:
            params["ssidNumber"] = ssid_number
        if login_identifier is not None:
            params["loginIdentifier"] = login_identifier
        if timespan is not None:
            params["timespan"] = timespan

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkSplashLoginAttempts",
            path=path,
            params=params,
            item_schema=GetNetworkSplashLoginAttemptsResponseItem,
        )

    async def split_network(self, network_id: str) -> SplitNetworkResponse:
        """Split a combined network into individual networks for each type of device.

        [API documentation: splitNetwork](https://developer.cisco.com/meraki/api-v1/#!split-network)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "resultingNetworks": [
                {
                  "id": "N_24329156",
                  "organizationId": "2930418",
                  "name": "Main Office - switch",
                  "productTypes": [
                    "switch"
                  ],
                  "timeZone": "America/Los_Angeles",
                  "tags": [
                    "tag1",
                    "tag2"
                  ],
                  "enrollmentString": "my-enrollment-string",
                  "url": "https://n1.meraki.com//n//manage/nodes/list",
                  "notes": "Additional description of the network",
                  "isBoundToConfigTemplate": false
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/split"

        return await self._session.post(
            scope="networks",
            operation_id="splitNetwork",
            path=path,
            response_schema=SplitNetworkResponse,
        )

    async def get_network_syslog_servers(self, network_id: str) -> GetNetworkSyslogServersResponse:
        """List the syslog servers for a network.

        [API documentation: getNetworkSyslogServers](https://developer.cisco.com/meraki/api-v1/#!get-network-syslog-servers)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "servers": [
                {
                  "host": "1.2.3.4",
                  "port": 443,
                  "roles": [
                    "Wireless event log",
                    "URLs"
                  ]
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/syslogServers"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkSyslogServers",
            path=path,
            response_schema=GetNetworkSyslogServersResponse,
        )

    async def update_network_syslog_servers(
        self, *, network_id: str, servers: list[UpdateNetworkSyslogServersServersItem]
    ) -> UpdateNetworkSyslogServersResponse:
        """Update the syslog servers for a network.

        [API documentation: updateNetworkSyslogServers](https://developer.cisco.com/meraki/api-v1/#!update-network-syslog-servers)

        Args:
            network_id: Network ID.
            servers: A list of the syslog servers for this network.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "servers": [
                {
                  "host": "1.2.3.4",
                  "port": 443,
                  "roles": [
                    "Wireless event log",
                    "URLs"
                  ]
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/syslogServers"

        payload: dict[str, Any] = {}
        if servers is not None:
            payload["servers"] = [
                item.model_dump(by_alias=True, exclude_none=True) for item in servers
            ]

        return await self._session.put(
            scope="networks",
            operation_id="updateNetworkSyslogServers",
            path=path,
            json=payload,
            response_schema=UpdateNetworkSyslogServersResponse,
        )

    async def get_network_topology_link_layer(
        self, network_id: str
    ) -> GetNetworkTopologyLinkLayerResponse:
        """List the LLDP and CDP information for all discovered devices and connections in a network.

        [API documentation: getNetworkTopologyLinkLayer](https://developer.cisco.com/meraki/api-v1/#!get-network-topology-link-layer)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "nodes": [
                {
                  "derivedId": "aabbccddeeff",
                  "mac": "AA:BB:CC:DD:EE:FF",
                  "type": "device",
                  "root": true,
                  "device": {
                    "serial": "Q2UN-A44e-CU4L",
                    "name": "Living Room Gateway",
                    "model": "GX20",
                    "productType": "appliance",
                    "status": "online",
                    "lastReportedAt": "2021-06-24T10:23:12z",
                    "clients": {
                      "counts": {
                        "total": 8
                      }
                    },
                    "uplinks": [
                      {
                        "vlanId": 0
                      }
                    ]
                  },
                  "discovered": {
                    "lldp": {
                      "chassisId": "12345",
                      "systemName": "Non-Meraki device",
                      "systemDescription": "Router and Switch Device",
                      "systemCapabilities": [
                        "router",
                        "switch"
                      ],
                      "managementAddress": "10.130.105.154"
                    },
                    "cdp": {
                      "platform": "Cisco IOS",
                      "deviceId": "switch01.example.com",
                      "address": "192.168.1.1",
                      "capabilities": [
                        "router",
                        "switch"
                      ],
                      "managementAddress": "192.168.1.1"
                    }
                  },
                  "stack": {
                    "id": 98765,
                    "name": "Corp Stack",
                    "clients": {
                      "counts": {
                        "total": 14
                      }
                    }
                  }
                }
              ],
              "links": [
                {
                  "ends": [
                    {
                      "node": {
                        "derivedId": "34564",
                        "type": "stack"
                      },
                      "device": {
                        "serial": "Q2UN-E55e-KO6L",
                        "name": "Study Switch 2"
                      },
                      "discovered": {
                        "lldp": {
                          "portId": "Port 20",
                          "portDescription": "eth0"
                        },
                        "cdp": {
                          "portId": "Port 20",
                          "nativeVlan": 102
                        }
                      }
                    }
                  ],
                  "lastReportedAt": "2021-06-25T14:56:27z"
                }
              ],
              "errors": []
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/topology/linkLayer"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkTopologyLinkLayer",
            path=path,
            response_schema=GetNetworkTopologyLinkLayerResponse,
        )

    def get_network_traffic(
        self,
        network_id: str,
        *,
        t0: str | None = None,
        timespan: float | None = None,
        device_type: GetNetworkTrafficDeviceType | None = None,
    ) -> AsyncPaginatedResponse[GetNetworkTrafficResponseItem]:
        """Return the traffic analysis data for this network.

        [API documentation: getNetworkTraffic](https://developer.cisco.com/meraki/api-v1/#!get-network-traffic)

        Args:
            network_id: Network ID.
            t0: The beginning of the timespan for the data. The maximum lookback period is 30 days
                from today.
            timespan: The timespan for which the information will be fetched. If specifying
                timespan, do not specify parameter t0. The value must be in seconds and
                be less than or equal to 30 days.
            device_type: Filter the data by device type: 'combined', 'wireless', 'switch' or
                'appliance'. Defaults to 'combined'. When using 'combined', for each
                rule the data will come from the device type with the most usage.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "application": "Gmail",
                "destination": "2.3.4.5",
                "protocol": "TCP",
                "port": 443,
                "sent": 138.0,
                "recv": 61.0,
                "numClients": 7,
                "activeTime": 77000,
                "flows": 300
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/traffic"

        params: dict[str, Any] = {}
        if t0 is not None:
            params["t0"] = t0
        if timespan is not None:
            params["timespan"] = timespan
        if device_type is not None:
            params["deviceType"] = device_type

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkTraffic",
            path=path,
            params=params,
            item_schema=GetNetworkTrafficResponseItem,
        )

    async def get_network_traffic_analysis(
        self, network_id: str
    ) -> GetNetworkTrafficAnalysisResponse:
        """Return the traffic analysis settings for a network.

        [API documentation: getNetworkTrafficAnalysis](https://developer.cisco.com/meraki/api-v1/#!get-network-traffic-analysis)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "mode": "disabled",
              "customPieChartItems": [
                {
                  "name": "Item from hostname",
                  "type": "host",
                  "value": "example.com"
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/trafficAnalysis"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkTrafficAnalysis",
            path=path,
            response_schema=GetNetworkTrafficAnalysisResponse,
        )

    async def update_network_traffic_analysis(
        self,
        network_id: str,
        *,
        mode: UpdateNetworkTrafficAnalysisMode | None = None,
        custom_pie_chart_items: list[UpdateNetworkTrafficAnalysisCustomPieChartItemsItem]
        | None = None,
    ) -> UpdateNetworkTrafficAnalysisResponse:
        """Update the traffic analysis settings for a network.

        [API documentation: updateNetworkTrafficAnalysis](https://developer.cisco.com/meraki/api-v1/#!update-network-traffic-analysis)

        Args:
            network_id: Network ID.
            mode: The traffic analysis mode for the network. Can be one of 'disabled' (do not
                collect traffic types), 'basic' (collect generic traffic categories), or
                'detailed' (collect destination hostnames).
            custom_pie_chart_items: The list of items that make up the custom pie chart for traffic
                reporting.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "mode": "disabled",
              "customPieChartItems": [
                {
                  "name": "Item from hostname",
                  "type": "host",
                  "value": "example.com"
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/trafficAnalysis"

        payload: dict[str, Any] = {}
        if mode is not None:
            payload["mode"] = mode
        if custom_pie_chart_items is not None:
            payload["customPieChartItems"] = [
                item.model_dump(by_alias=True, exclude_none=True) for item in custom_pie_chart_items
            ]

        return await self._session.put(
            scope="networks",
            operation_id="updateNetworkTrafficAnalysis",
            path=path,
            json=payload,
            response_schema=UpdateNetworkTrafficAnalysisResponse,
        )

    async def get_network_traffic_shaping_application_categories(
        self, network_id: str
    ) -> DictResponse:
        """Returns the application categories for traffic shaping rules.

        [API documentation: getNetworkTrafficShapingApplicationCategories](https://developer.cisco.com/meraki/api-v1/#!get-network-traffic-shaping-application-categories)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "applicationCategories": [
                {
                  "id": "meraki:layer7/category/24",
                  "name": "Advertising",
                  "applications": [
                    {
                      "id": "meraki:layer7/application/5",
                      "name": "Advertising.com"
                    },
                    {
                      "id": "meraki:layer7/application/0",
                      "name": "AppNexus"
                    },
                    {
                      "id": "meraki:layer7/application/1",
                      "name": "Brightroll"
                    }
                  ]
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/trafficShaping/applicationCategories"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkTrafficShapingApplicationCategories",
            path=path,
            response_schema=DictResponse,
        )

    def get_network_traffic_shaping_dscp_tagging_options(
        self, network_id: str
    ) -> AsyncPaginatedResponse[GetNetworkTrafficShapingDscpTaggingOptionsResponse]:
        """Returns the available DSCP tagging options for your traffic shaping rules.

        [API documentation: getNetworkTrafficShapingDscpTaggingOptions](https://developer.cisco.com/meraki/api-v1/#!get-network-traffic-shaping-dscp-tagging-options)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "dscpTagValue": 10,
                "description": "AF11 - High Throughput, Latency Insensitive, Low Drop"
              },
              {
                "dscpTagValue": 12,
                "description": "AF12 - High Throughput, Latency Insensitive, Medium Drop"
              },
              {
                "dscpTagValue": 14,
                "description": "AF13 - High Throughput, Latency Insensitive, High Drop"
              },
              {
                "dscpTagValue": 18,
                "description": "AF21 - Low Latency Data, Low Drop"
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/trafficShaping/dscpTaggingOptions"

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkTrafficShapingDscpTaggingOptions",
            path=path,
            item_schema=GetNetworkTrafficShapingDscpTaggingOptionsResponse,
        )

    async def unbind_network(
        self, network_id: str, *, retain_configs: bool | None = None
    ) -> UnbindNetworkResponse:
        """Unbind a network from a template.

        [API documentation: unbindNetwork](https://developer.cisco.com/meraki/api-v1/#!unbind-network)

        Args:
            network_id: Network ID.
            retain_configs: Optional boolean to retain all the current configs given by the
                template.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "id": "N_24329156",
              "organizationId": "2930418",
              "name": "Main Office",
              "productTypes": [
                "appliance",
                "switch",
                "wireless"
              ],
              "timeZone": "America/Los_Angeles",
              "tags": [
                "tag1",
                "tag2"
              ],
              "enrollmentString": "my-enrollment-string",
              "url": "https://n1.meraki.com//n//manage/nodes/list",
              "notes": "Additional description of the network",
              "isBoundToConfigTemplate": false
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/unbind"

        payload: dict[str, Any] = {}
        if retain_configs is not None:
            payload["retainConfigs"] = retain_configs

        return await self._session.post(
            scope="networks",
            operation_id="unbindNetwork",
            path=path,
            json=payload,
            response_schema=UnbindNetworkResponse,
        )

    def get_network_vlan_profiles(
        self, network_id: str
    ) -> AsyncPaginatedResponse[GetNetworkVlanProfilesResponseItem]:
        """List VLAN profiles for a network.

        [API documentation: getNetworkVlanProfiles](https://developer.cisco.com/meraki/api-v1/#!get-network-vlan-profiles)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "iname": "Profile1",
                "name": "My VLAN profile name",
                "isDefault": false,
                "vlanNames": [
                  {
                    "name": "named-1",
                    "vlanId": "1",
                    "adaptivePolicyGroup": {
                      "id": "791",
                      "name": "Infrastructure"
                    }
                  }
                ],
                "vlanGroups": [
                  {
                    "name": "named-group-1",
                    "vlanIds": "2,5-7"
                  }
                ]
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/vlanProfiles"

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkVlanProfiles",
            path=path,
            item_schema=GetNetworkVlanProfilesResponseItem,
        )

    async def create_network_vlan_profile(
        self,
        *,
        network_id: str,
        name: str,
        vlan_names: list[CreateNetworkVlanProfileVlanNamesItem],
        vlan_groups: list[CreateNetworkVlanProfileVlanGroupsItem],
        iname: str,
    ) -> CreateNetworkVlanProfileResponse:
        """Create a VLAN profile for a network.

        [API documentation: createNetworkVlanProfile](https://developer.cisco.com/meraki/api-v1/#!create-network-vlan-profile)

        Args:
            network_id: Network ID.
            name: Name of the profile, string length must be from 1 to 255 characters.
            vlan_names: An array of named VLANs.
            vlan_groups: An array of VLAN groups.
            iname: IName of the profile.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "iname": "Profile1",
              "name": "My VLAN profile name",
              "isDefault": false,
              "vlanNames": [
                {
                  "name": "named-1",
                  "vlanId": "1",
                  "adaptivePolicyGroup": {
                    "id": "791",
                    "name": "Infrastructure"
                  }
                }
              ],
              "vlanGroups": [
                {
                  "name": "named-group-1",
                  "vlanIds": "2,5-7"
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/vlanProfiles"

        payload: dict[str, Any] = {}
        if name is not None:
            payload["name"] = name
        if vlan_names is not None:
            payload["vlanNames"] = [
                item.model_dump(by_alias=True, exclude_none=True) for item in vlan_names
            ]
        if vlan_groups is not None:
            payload["vlanGroups"] = [
                item.model_dump(by_alias=True, exclude_none=True) for item in vlan_groups
            ]
        if iname is not None:
            payload["iname"] = iname

        return await self._session.post(
            scope="networks",
            operation_id="createNetworkVlanProfile",
            path=path,
            json=payload,
            response_schema=CreateNetworkVlanProfileResponse,
        )

    def get_network_vlan_profiles_assignments_by_device(
        self,
        network_id: str,
        *,
        per_page: int | None = None,
        starting_after: str | None = None,
        ending_before: str | None = None,
        serials: list[str] | None = None,
        product_types: GetNetworkVlanProfilesAssignmentsByDeviceProductTypes | None = None,
        stack_ids: list[str] | None = None,
        total_pages: int | Literal["all"] = "all",
        direction: Literal["prev", "next"] = "next",
    ) -> AsyncPaginatedResponse[GetNetworkVlanProfilesAssignmentsByDeviceResponseItem]:
        """Get the assigned VLAN Profiles for devices in a network.

        [API documentation: getNetworkVlanProfilesAssignmentsByDevice](https://developer.cisco.com/meraki/api-v1/#!get-network-vlan-profiles-assignments-by-device)

        Args:
            network_id: Network ID.
            per_page: The number of entries per page returned. Acceptable range is 3 - 1000. Default
                is 1000.
            starting_after: A token used by the server to indicate the start of the page. Often this
                is a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            ending_before: A token used by the server to indicate the end of the page. Often this is
                a timestamp or an ID but it is not limited to those. This parameter
                should not be defined by client applications. The link for the first,
                last, prev, or next page in the HTTP Link header should define it.
            serials: Optional parameter to filter devices by serials. All devices returned belong to
                serial numbers that are an exact match.
            product_types: Optional parameter to filter devices by product types.
            stack_ids: Optional parameter to filter devices by Switch Stack ids.
            total_pages: use with per_page to get total results up to total_pages * per_page; -1 or
                "all" for all pages.
            direction: direction to paginate, either "next" (default) or "prev" page.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "name": "My switch",
                "serial": "Q234-ABCD-5678",
                "mac": "00:11:22:33:44:55",
                "productType": "switch",
                "vlanProfile": {
                  "iname": "Profile1",
                  "name": "My VLAN Profile",
                  "isDefault": true
                },
                "stack": {
                  "id": "1234"
                }
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/vlanProfiles/assignments/byDevice"

        params: dict[str, Any] = {}
        if per_page is not None:
            params["perPage"] = per_page
        if starting_after is not None:
            params["startingAfter"] = starting_after
        if ending_before is not None:
            params["endingBefore"] = ending_before
        if serials is not None:
            params["serials[]"] = serials
        if product_types is not None:
            params["productTypes[]"] = product_types
        if stack_ids is not None:
            params["stackIds[]"] = stack_ids

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkVlanProfilesAssignmentsByDevice",
            path=path,
            params=params,
            total_pages=total_pages,
            direction=direction,
            item_schema=GetNetworkVlanProfilesAssignmentsByDeviceResponseItem,
        )

    async def reassign_network_vlan_profiles_assignments(
        self,
        *,
        network_id: str,
        serials: list[str],
        stack_ids: list[str],
        vlan_profile: ReassignNetworkVlanProfilesAssignmentsVlanProfile | None = None,
    ) -> ReassignNetworkVlanProfilesAssignmentsResponse:
        """Update the assigned VLAN Profile for devices in a network.

        [API documentation: reassignNetworkVlanProfilesAssignments](https://developer.cisco.com/meraki/api-v1/#!reassign-network-vlan-profiles-assignments)

        Args:
            network_id: Network ID.
            vlan_profile: The VLAN Profile.
            serials: Array of Device Serials.
            stack_ids: Array of Switch Stack IDs.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "vlanProfile": {
                "iname": "Profile1",
                "name": "My VLAN Profile"
              },
              "serials": [
                "Q234-ABCD-5678"
              ],
              "stackIds": [
                "1234"
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/vlanProfiles/assignments/reassign"

        payload: dict[str, Any] = {}
        if vlan_profile is not None:
            payload["vlanProfile"] = vlan_profile.model_dump(by_alias=True, exclude_none=True)
        if serials is not None:
            payload["serials"] = serials
        if stack_ids is not None:
            payload["stackIds"] = stack_ids

        return await self._session.post(
            scope="networks",
            operation_id="reassignNetworkVlanProfilesAssignments",
            path=path,
            json=payload,
            response_schema=ReassignNetworkVlanProfilesAssignmentsResponse,
        )

    async def get_network_vlan_profile(
        self, *, network_id: str, iname: str
    ) -> GetNetworkVlanProfileResponse:
        """Get an existing VLAN profile of a network.

        [API documentation: getNetworkVlanProfile](https://developer.cisco.com/meraki/api-v1/#!get-network-vlan-profile)

        Args:
            network_id: Network ID.
            iname: Iname.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "iname": "Profile1",
              "name": "My VLAN profile name",
              "isDefault": false,
              "vlanNames": [
                {
                  "name": "named-1",
                  "vlanId": "1",
                  "adaptivePolicyGroup": {
                    "id": "791",
                    "name": "Infrastructure"
                  }
                }
              ],
              "vlanGroups": [
                {
                  "name": "named-group-1",
                  "vlanIds": "2,5-7"
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        iname = urllib.parse.quote(str(iname), safe="")
        path = f"/networks/{network_id}/vlanProfiles/{iname}"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkVlanProfile",
            path=path,
            response_schema=GetNetworkVlanProfileResponse,
        )

    async def update_network_vlan_profile(
        self,
        *,
        network_id: str,
        iname: str,
        name: str,
        vlan_names: list[UpdateNetworkVlanProfileVlanNamesItem],
        vlan_groups: list[UpdateNetworkVlanProfileVlanGroupsItem],
    ) -> UpdateNetworkVlanProfileResponse:
        """Update an existing VLAN profile of a network.

        [API documentation: updateNetworkVlanProfile](https://developer.cisco.com/meraki/api-v1/#!update-network-vlan-profile)

        Args:
            network_id: Network ID.
            iname: Iname.
            name: Name of the profile, string length must be from 1 to 255 characters.
            vlan_names: An array of named VLANs.
            vlan_groups: An array of VLAN groups.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "iname": "Profile1",
              "name": "My VLAN profile name",
              "isDefault": false,
              "vlanNames": [
                {
                  "name": "named-1",
                  "vlanId": "1",
                  "adaptivePolicyGroup": {
                    "id": "791",
                    "name": "Infrastructure"
                  }
                }
              ],
              "vlanGroups": [
                {
                  "name": "named-group-1",
                  "vlanIds": "2,5-7"
                }
              ]
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        iname = urllib.parse.quote(str(iname), safe="")
        path = f"/networks/{network_id}/vlanProfiles/{iname}"

        payload: dict[str, Any] = {}
        if name is not None:
            payload["name"] = name
        if vlan_names is not None:
            payload["vlanNames"] = [
                item.model_dump(by_alias=True, exclude_none=True) for item in vlan_names
            ]
        if vlan_groups is not None:
            payload["vlanGroups"] = [
                item.model_dump(by_alias=True, exclude_none=True) for item in vlan_groups
            ]

        return await self._session.put(
            scope="networks",
            operation_id="updateNetworkVlanProfile",
            path=path,
            json=payload,
            response_schema=UpdateNetworkVlanProfileResponse,
        )

    async def delete_network_vlan_profile(self, *, network_id: str, iname: str) -> None:
        """Delete a VLAN profile of a network.

        [API documentation: deleteNetworkVlanProfile](https://developer.cisco.com/meraki/api-v1/#!delete-network-vlan-profile)

        Args:
            network_id: Network ID.
            iname: Iname.

        Returns:
            Successful operation.

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        iname = urllib.parse.quote(str(iname), safe="")
        path = f"/networks/{network_id}/vlanProfiles/{iname}"

        return await self._session.delete(
            scope="networks", operation_id="deleteNetworkVlanProfile", path=path
        )

    def get_network_webhooks_http_servers(
        self, network_id: str
    ) -> AsyncPaginatedResponse[GetNetworkWebhooksHttpServersResponseItem]:
        """List the HTTP servers for a network.

        [API documentation: getNetworkWebhooksHttpServers](https://developer.cisco.com/meraki/api-v1/#!get-network-webhooks-http-servers)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "id": "aHR0cHM6Ly93d3cuZXhhbXBsZS5jb20vbXlfY3VzdG9tX3dlYmhvb2s=",
                "name": "Example Webhook Server",
                "url": "https://www.example.com/my_custom_webhook",
                "networkId": "N_12345678",
                "payloadTemplate": {
                  "payloadTemplateId": "wpt_00001",
                  "name": "Meraki (included)"
                }
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/webhooks/httpServers"

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkWebhooksHttpServers",
            path=path,
            item_schema=GetNetworkWebhooksHttpServersResponseItem,
        )

    async def create_network_webhooks_http_server(
        self,
        *,
        network_id: str,
        name: str,
        url: str,
        shared_secret: str | None = None,
        payload_template: CreateNetworkWebhooksHttpServerPayloadTemplate | None = None,
    ) -> CreateNetworkWebhooksHttpServerResponse:
        """Add an HTTP server to a network.

        [API documentation: createNetworkWebhooksHttpServer](https://developer.cisco.com/meraki/api-v1/#!create-network-webhooks-http-server)

        Args:
            network_id: Network ID.
            name: A name for easy reference to the HTTP server.
            url: The URL of the HTTP server. Once set, cannot be updated.
            shared_secret: A shared secret that will be included in POSTs sent to the HTTP server.
                This secret can be used to verify that the request was sent by Meraki.
            payload_template: The payload template to use when posting data to the HTTP server.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "id": "aHR0cHM6Ly93d3cuZXhhbXBsZS5jb20vbXlfY3VzdG9tX3dlYmhvb2s=",
              "name": "Example Webhook Server",
              "url": "https://www.example.com/my_custom_webhook",
              "networkId": "N_12345678",
              "payloadTemplate": {
                "payloadTemplateId": "wpt_00001",
                "name": "Meraki (included)"
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/webhooks/httpServers"

        payload: dict[str, Any] = {}
        if name is not None:
            payload["name"] = name
        if url is not None:
            payload["url"] = url
        if shared_secret is not None:
            payload["sharedSecret"] = shared_secret
        if payload_template is not None:
            payload["payloadTemplate"] = payload_template.model_dump(
                by_alias=True, exclude_none=True
            )

        return await self._session.post(
            scope="networks",
            operation_id="createNetworkWebhooksHttpServer",
            path=path,
            json=payload,
            response_schema=CreateNetworkWebhooksHttpServerResponse,
        )

    async def get_network_webhooks_http_server(
        self, *, network_id: str, http_server_id: str
    ) -> GetNetworkWebhooksHttpServerResponse:
        """Return an HTTP server for a network.

        [API documentation: getNetworkWebhooksHttpServer](https://developer.cisco.com/meraki/api-v1/#!get-network-webhooks-http-server)

        Args:
            network_id: Network ID.
            http_server_id: Http server ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "id": "aHR0cHM6Ly93d3cuZXhhbXBsZS5jb20vbXlfY3VzdG9tX3dlYmhvb2s=",
              "name": "Example Webhook Server",
              "url": "https://www.example.com/my_custom_webhook",
              "networkId": "N_12345678",
              "payloadTemplate": {
                "payloadTemplateId": "wpt_00001",
                "name": "Meraki (included)"
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        http_server_id = urllib.parse.quote(str(http_server_id), safe="")
        path = f"/networks/{network_id}/webhooks/httpServers/{http_server_id}"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkWebhooksHttpServer",
            path=path,
            response_schema=GetNetworkWebhooksHttpServerResponse,
        )

    async def update_network_webhooks_http_server(
        self,
        *,
        network_id: str,
        http_server_id: str,
        name: str | None = None,
        shared_secret: str | None = None,
        payload_template: UpdateNetworkWebhooksHttpServerPayloadTemplate | None = None,
    ) -> UpdateNetworkWebhooksHttpServerResponse:
        """Update an HTTP server.

        [API documentation: updateNetworkWebhooksHttpServer](https://developer.cisco.com/meraki/api-v1/#!update-network-webhooks-http-server)

        Args:
            network_id: Network ID.
            http_server_id: Http server ID.
            name: A name for easy reference to the HTTP server.
            shared_secret: A shared secret that will be included in POSTs sent to the HTTP server.
                This secret can be used to verify that the request was sent by Meraki.
            payload_template: The payload template to use when posting data to the HTTP server.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "id": "aHR0cHM6Ly93d3cuZXhhbXBsZS5jb20vbXlfY3VzdG9tX3dlYmhvb2s=",
              "name": "Example Webhook Server",
              "url": "https://www.example.com/my_custom_webhook",
              "networkId": "N_12345678",
              "payloadTemplate": {
                "payloadTemplateId": "wpt_00001",
                "name": "Meraki (included)"
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        http_server_id = urllib.parse.quote(str(http_server_id), safe="")
        path = f"/networks/{network_id}/webhooks/httpServers/{http_server_id}"

        payload: dict[str, Any] = {}
        if name is not None:
            payload["name"] = name
        if shared_secret is not None:
            payload["sharedSecret"] = shared_secret
        if payload_template is not None:
            payload["payloadTemplate"] = payload_template.model_dump(
                by_alias=True, exclude_none=True
            )

        return await self._session.put(
            scope="networks",
            operation_id="updateNetworkWebhooksHttpServer",
            path=path,
            json=payload,
            response_schema=UpdateNetworkWebhooksHttpServerResponse,
        )

    async def delete_network_webhooks_http_server(
        self, *, network_id: str, http_server_id: str
    ) -> None:
        """Delete an HTTP server from a network.

        [API documentation: deleteNetworkWebhooksHttpServer](https://developer.cisco.com/meraki/api-v1/#!delete-network-webhooks-http-server)

        Args:
            network_id: Network ID.
            http_server_id: Http server ID.

        Returns:
            Successful operation.

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        http_server_id = urllib.parse.quote(str(http_server_id), safe="")
        path = f"/networks/{network_id}/webhooks/httpServers/{http_server_id}"

        return await self._session.delete(
            scope="networks", operation_id="deleteNetworkWebhooksHttpServer", path=path
        )

    def get_network_webhooks_payload_templates(
        self, network_id: str
    ) -> AsyncPaginatedResponse[GetNetworkWebhooksPayloadTemplatesResponseItem]:
        r"""List the webhook payload templates for a network.

        [API documentation: getNetworkWebhooksPayloadTemplates](https://developer.cisco.com/meraki/api-v1/#!get-network-webhooks-payload-templates)

        Args:
            network_id: Network ID.

        Returns:
            Successful operation.

        Note:
            Returns a lazy AsyncPaginatedResponse
            that can be iterated or collected with `.collect()`.
            Page metadata is available on `.meta` and `.meta_pages`.

        Example API response:
            ```json
            [
              {
                "payloadTemplateId": "wpt_343",
                "type": "custom",
                "name": "Custom Template",
                "headers": [
                  {
                    "name": "Authorization",
                    "template": "Bearer {{sharedSecret}}"
                  }
                ],
                "body": "{\"event_type\":\"{{alertTypeId}}\",\"client_payload\":{\"text\":\"{{alertData}}\"}}",
                "sharing": {
                  "byNetwork": {
                    "adminsCanModify": false
                  }
                }
              }
            ]
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/webhooks/payloadTemplates"

        return self._session.get_pages(
            scope="networks",
            operation_id="getNetworkWebhooksPayloadTemplates",
            path=path,
            item_schema=GetNetworkWebhooksPayloadTemplatesResponseItem,
        )

    async def create_network_webhooks_payload_template(
        self,
        *,
        network_id: str,
        name: str,
        body: str | None = None,
        headers: list[CreateNetworkWebhooksPayloadTemplateHeadersItem] | None = None,
        body_file: str | None = None,
        headers_file: str | None = None,
    ) -> CreateNetworkWebhooksPayloadTemplateResponse:
        r"""Create a webhook payload template for a network.

        [API documentation: createNetworkWebhooksPayloadTemplate](https://developer.cisco.com/meraki/api-v1/#!create-network-webhooks-payload-template)

        Args:
            network_id: Network ID.
            name: The name of the new template.
            body: The liquid template used for the body of the webhook message. Either `body` or
                `bodyFile` must be specified.
            headers: The liquid template used with the webhook headers.
            body_file: A Base64 encoded file containing liquid template used for the body of the
                webhook message. Either `body` or `bodyFile` must be specified.
            headers_file: A Base64 encoded file containing the liquid template used with the webhook
                headers.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "payloadTemplateId": "wpt_343",
              "type": "custom",
              "name": "Custom Template",
              "headers": [
                {
                  "name": "Authorization",
                  "template": "Bearer {{sharedSecret}}"
                }
              ],
              "body": "{\"event_type\":\"{{alertTypeId}}\",\"client_payload\":{\"text\":\"{{alertData}}\"}}",
              "sharing": {
                "byNetwork": {
                  "adminsCanModify": false
                }
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/webhooks/payloadTemplates"

        payload: dict[str, Any] = {}
        if name is not None:
            payload["name"] = name
        if body is not None:
            payload["body"] = body
        if headers is not None:
            payload["headers"] = [
                item.model_dump(by_alias=True, exclude_none=True) for item in headers
            ]
        if body_file is not None:
            payload["bodyFile"] = body_file
        if headers_file is not None:
            payload["headersFile"] = headers_file

        return await self._session.post(
            scope="networks",
            operation_id="createNetworkWebhooksPayloadTemplate",
            path=path,
            json=payload,
            response_schema=CreateNetworkWebhooksPayloadTemplateResponse,
        )

    async def get_network_webhooks_payload_template(
        self, *, network_id: str, payload_template_id: str
    ) -> GetNetworkWebhooksPayloadTemplateResponse:
        r"""Get the webhook payload template for a network.

        [API documentation: getNetworkWebhooksPayloadTemplate](https://developer.cisco.com/meraki/api-v1/#!get-network-webhooks-payload-template)

        Args:
            network_id: Network ID.
            payload_template_id: Payload template ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "payloadTemplateId": "wpt_343",
              "type": "custom",
              "name": "Custom Template",
              "headers": [
                {
                  "name": "Authorization",
                  "template": "Bearer {{sharedSecret}}"
                }
              ],
              "body": "{\"event_type\":\"{{alertTypeId}}\",\"client_payload\":{\"text\":\"{{alertData}}\"}}",
              "sharing": {
                "byNetwork": {
                  "adminsCanModify": false
                }
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        payload_template_id = urllib.parse.quote(str(payload_template_id), safe="")
        path = f"/networks/{network_id}/webhooks/payloadTemplates/{payload_template_id}"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkWebhooksPayloadTemplate",
            path=path,
            response_schema=GetNetworkWebhooksPayloadTemplateResponse,
        )

    async def update_network_webhooks_payload_template(
        self,
        *,
        network_id: str,
        payload_template_id: str,
        name: str | None = None,
        body: str | None = None,
        headers: list[UpdateNetworkWebhooksPayloadTemplateHeadersItem] | None = None,
        body_file: str | None = None,
        headers_file: str | None = None,
    ) -> UpdateNetworkWebhooksPayloadTemplateResponse:
        r"""Update a webhook payload template for a network.

        [API documentation: updateNetworkWebhooksPayloadTemplate](https://developer.cisco.com/meraki/api-v1/#!update-network-webhooks-payload-template)

        Args:
            network_id: Network ID.
            payload_template_id: Payload template ID.
            name: The name of the template.
            body: The liquid template used for the body of the webhook message.
            headers: The liquid template used with the webhook headers.
            body_file: A file containing liquid template used for the body of the webhook message.
            headers_file: A file containing the liquid template used with the webhook headers.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "payloadTemplateId": "wpt_343",
              "type": "custom",
              "name": "Custom Template",
              "headers": [
                {
                  "name": "Authorization",
                  "template": "Bearer {{sharedSecret}}"
                }
              ],
              "body": "{\"event_type\":\"{{alertTypeId}}\",\"client_payload\":{\"text\":\"{{alertData}}\"}}",
              "sharing": {
                "byNetwork": {
                  "adminsCanModify": false
                }
              }
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        payload_template_id = urllib.parse.quote(str(payload_template_id), safe="")
        path = f"/networks/{network_id}/webhooks/payloadTemplates/{payload_template_id}"

        payload: dict[str, Any] = {}
        if name is not None:
            payload["name"] = name
        if body is not None:
            payload["body"] = body
        if headers is not None:
            payload["headers"] = [
                item.model_dump(by_alias=True, exclude_none=True) for item in headers
            ]
        if body_file is not None:
            payload["bodyFile"] = body_file
        if headers_file is not None:
            payload["headersFile"] = headers_file

        return await self._session.put(
            scope="networks",
            operation_id="updateNetworkWebhooksPayloadTemplate",
            path=path,
            json=payload,
            response_schema=UpdateNetworkWebhooksPayloadTemplateResponse,
        )

    async def delete_network_webhooks_payload_template(
        self, *, network_id: str, payload_template_id: str
    ) -> None:
        """Destroy a webhook payload template for a network.

        [API documentation: deleteNetworkWebhooksPayloadTemplate](https://developer.cisco.com/meraki/api-v1/#!delete-network-webhooks-payload-template)

        Args:
            network_id: Network ID.
            payload_template_id: Payload template ID.

        Returns:
            Successful operation.

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        payload_template_id = urllib.parse.quote(str(payload_template_id), safe="")
        path = f"/networks/{network_id}/webhooks/payloadTemplates/{payload_template_id}"

        return await self._session.delete(
            scope="networks", operation_id="deleteNetworkWebhooksPayloadTemplate", path=path
        )

    async def create_network_webhooks_webhook_test(
        self,
        *,
        network_id: str,
        url: str,
        shared_secret: str | None = None,
        payload_template_id: str | None = None,
        payload_template_name: str | None = None,
        alert_type_id: str | None = None,
    ) -> CreateNetworkWebhooksWebhookTestResponse:
        """Send a test webhook for a network.

        [API documentation: createNetworkWebhooksWebhookTest](https://developer.cisco.com/meraki/api-v1/#!create-network-webhooks-webhook-test)

        Args:
            network_id: Network ID.
            url: The URL where the test webhook will be sent.
            shared_secret: The shared secret the test webhook will send. Optional. Defaults to HTTP
                server's shared secret. Otherwise, defaults to an empty string.
            payload_template_id: The ID of the payload template of the test webhook. Defaults to the
                HTTP server's template ID if one exists for the given URL, or Generic
                template ID otherwise.
            payload_template_name: The name of the payload template.
            alert_type_id: The type of alert which the test webhook will send. Optional. Defaults to
                power_supply_down.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "id": "1234",
              "url": "https://www.example.com/path",
              "status": "enqueued"
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        path = f"/networks/{network_id}/webhooks/webhookTests"

        payload: dict[str, Any] = {}
        if url is not None:
            payload["url"] = url
        if shared_secret is not None:
            payload["sharedSecret"] = shared_secret
        if payload_template_id is not None:
            payload["payloadTemplateId"] = payload_template_id
        if payload_template_name is not None:
            payload["payloadTemplateName"] = payload_template_name
        if alert_type_id is not None:
            payload["alertTypeId"] = alert_type_id

        return await self._session.post(
            scope="networks",
            operation_id="createNetworkWebhooksWebhookTest",
            path=path,
            json=payload,
            response_schema=CreateNetworkWebhooksWebhookTestResponse,
        )

    async def get_network_webhooks_webhook_test(
        self, *, network_id: str, webhook_test_id: str
    ) -> GetNetworkWebhooksWebhookTestResponse:
        """Return the status of a webhook test for a network.

        [API documentation: getNetworkWebhooksWebhookTest](https://developer.cisco.com/meraki/api-v1/#!get-network-webhooks-webhook-test)

        Args:
            network_id: Network ID.
            webhook_test_id: Webhook test ID.

        Returns:
            Successful operation.

        Example API response:
            ```json
            {
              "id": "1234",
              "url": "https://www.example.com/path",
              "status": "enqueued"
            }
            ```

        """
        network_id = urllib.parse.quote(str(network_id), safe="")
        webhook_test_id = urllib.parse.quote(str(webhook_test_id), safe="")
        path = f"/networks/{network_id}/webhooks/webhookTests/{webhook_test_id}"

        return await self._session.get(
            scope="networks",
            operation_id="getNetworkWebhooksWebhookTest",
            path=path,
            response_schema=GetNetworkWebhooksWebhookTestResponse,
        )
