diff --git a/PKG-INFO b/PKG-INFO
index 54c033c0908982655b29123ccf983f210d3b27c3..3926662beb4e6a7785c952432edeab38bf2a935f 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: hcloud
-Version: 1.24.0
+Version: 1.25.0
 Summary: Official Hetzner Cloud python library
 Home-page: https://github.com/hetznercloud/hcloud-python
 Author: Hetzner Cloud GmbH
diff --git a/hcloud.egg-info/PKG-INFO b/hcloud.egg-info/PKG-INFO
index 54c033c0908982655b29123ccf983f210d3b27c3..3926662beb4e6a7785c952432edeab38bf2a935f 100644
--- a/hcloud.egg-info/PKG-INFO
+++ b/hcloud.egg-info/PKG-INFO
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: hcloud
-Version: 1.24.0
+Version: 1.25.0
 Summary: Official Hetzner Cloud python library
 Home-page: https://github.com/hetznercloud/hcloud-python
 Author: Hetzner Cloud GmbH
diff --git a/hcloud.egg-info/SOURCES.txt b/hcloud.egg-info/SOURCES.txt
index e0597a65102ca376c24824797f03f7a094ad56b7..23e2990ff9a117992babd40181e344cb5ad7b5e6 100644
--- a/hcloud.egg-info/SOURCES.txt
+++ b/hcloud.egg-info/SOURCES.txt
@@ -36,6 +36,7 @@ docs/_static/logo-hetzner-online.svg
 docs/_static/js/open_links_in_new_tab.js
 hcloud/__init__.py
 hcloud/__version__.py
+hcloud/_client.py
 hcloud/_exceptions.py
 hcloud/hcloud.py
 hcloud.egg-info/PKG-INFO
@@ -105,6 +106,7 @@ hcloud/volumes/domain.py
 tests/__init__.py
 tests/unit/__init__.py
 tests/unit/conftest.py
+tests/unit/test_client.py
 tests/unit/test_hcloud.py
 tests/unit/actions/__init__.py
 tests/unit/actions/conftest.py
diff --git a/hcloud/__init__.py b/hcloud/__init__.py
index 592ff64d6d27c1b3f4b4f69492025a6a726fa1f2..5beda91d29f79eb24886eec78c3c0a6afbeadf56 100644
--- a/hcloud/__init__.py
+++ b/hcloud/__init__.py
@@ -1,2 +1,2 @@
+from ._client import Client  # noqa
 from ._exceptions import APIException, HCloudException  # noqa
-from .hcloud import Client  # noqa
diff --git a/hcloud/__version__.py b/hcloud/__version__.py
index 0c992210039dd305c397baa838d333543a0475a8..61abd10ca66c40a1c7c24bcbb38717a881d209ee 100644
--- a/hcloud/__version__.py
+++ b/hcloud/__version__.py
@@ -1 +1 @@
-VERSION = "1.24.0"  # x-release-please-version
+VERSION = "1.25.0"  # x-release-please-version
diff --git a/hcloud/_client.py b/hcloud/_client.py
new file mode 100644
index 0000000000000000000000000000000000000000..e62624f1610bad9a3fd0d015d8403ac7c165e9ce
--- /dev/null
+++ b/hcloud/_client.py
@@ -0,0 +1,222 @@
+import time
+from typing import Optional, Union
+
+import requests
+
+from .__version__ import VERSION
+from ._exceptions import APIException
+from .actions.client import ActionsClient
+from .certificates.client import CertificatesClient
+from .datacenters.client import DatacentersClient
+from .firewalls.client import FirewallsClient
+from .floating_ips.client import FloatingIPsClient
+from .images.client import ImagesClient
+from .isos.client import IsosClient
+from .load_balancer_types.client import LoadBalancerTypesClient
+from .load_balancers.client import LoadBalancersClient
+from .locations.client import LocationsClient
+from .networks.client import NetworksClient
+from .placement_groups.client import PlacementGroupsClient
+from .primary_ips.client import PrimaryIPsClient
+from .server_types.client import ServerTypesClient
+from .servers.client import ServersClient
+from .ssh_keys.client import SSHKeysClient
+from .volumes.client import VolumesClient
+
+
+class Client:
+    """Base Client for accessing the Hetzner Cloud API"""
+
+    _version = VERSION
+    _retry_wait_time = 0.5
+    __user_agent_prefix = "hcloud-python"
+
+    def __init__(
+        self,
+        token: str,
+        api_endpoint: str = "https://api.hetzner.cloud/v1",
+        application_name: Optional[str] = None,
+        application_version: Optional[str] = None,
+        poll_interval: int = 1,
+    ):
+        """Create an new Client instance
+
+        :param token: Hetzner Cloud API token
+        :param api_endpoint: Hetzner Cloud API endpoint
+        :param application_name: Your application name
+        :param application_version: Your application _version
+        :param poll_interval: Interval for polling information from Hetzner Cloud API in seconds
+        """
+        self.token = token
+        self._api_endpoint = api_endpoint
+        self._application_name = application_name
+        self._application_version = application_version
+        self._requests_session = requests.Session()
+        self.poll_interval = poll_interval
+
+        self.datacenters = DatacentersClient(self)
+        """DatacentersClient Instance
+
+        :type: :class:`DatacentersClient <hcloud.datacenters.client.DatacentersClient>`
+        """
+        self.locations = LocationsClient(self)
+        """LocationsClient Instance
+
+        :type: :class:`LocationsClient <hcloud.locations.client.LocationsClient>`
+        """
+        self.servers = ServersClient(self)
+        """ServersClient Instance
+
+        :type: :class:`ServersClient <hcloud.servers.client.ServersClient>`
+        """
+        self.server_types = ServerTypesClient(self)
+        """ServerTypesClient Instance
+
+        :type: :class:`ServerTypesClient <hcloud.server_types.client.ServerTypesClient>`
+        """
+        self.volumes = VolumesClient(self)
+        """VolumesClient Instance
+
+        :type: :class:`VolumesClient <hcloud.volumes.client.VolumesClient>`
+        """
+        self.actions = ActionsClient(self)
+        """ActionsClient Instance
+
+        :type: :class:`ActionsClient <hcloud.actions.client.ActionsClient>`
+        """
+        self.images = ImagesClient(self)
+        """ImagesClient Instance
+
+        :type: :class:`ImagesClient <hcloud.images.client.ImagesClient>`
+        """
+        self.isos = IsosClient(self)
+        """ImagesClient Instance
+
+        :type: :class:`IsosClient <hcloud.isos.client.IsosClient>`
+        """
+        self.ssh_keys = SSHKeysClient(self)
+        """SSHKeysClient Instance
+
+        :type: :class:`SSHKeysClient <hcloud.ssh_keys.client.SSHKeysClient>`
+        """
+        self.floating_ips = FloatingIPsClient(self)
+        """FloatingIPsClient Instance
+
+        :type: :class:`FloatingIPsClient <hcloud.floating_ips.client.FloatingIPsClient>`
+        """
+        self.primary_ips = PrimaryIPsClient(self)
+        """PrimaryIPsClient Instance
+
+        :type: :class:`PrimaryIPsClient <hcloud.primary_ips.client.PrimaryIPsClient>`
+        """
+        self.networks = NetworksClient(self)
+        """NetworksClient Instance
+
+        :type: :class:`NetworksClient <hcloud.networks.client.NetworksClient>`
+        """
+        self.certificates = CertificatesClient(self)
+        """CertificatesClient Instance
+
+        :type: :class:`CertificatesClient <hcloud.certificates.client.CertificatesClient>`
+        """
+
+        self.load_balancers = LoadBalancersClient(self)
+        """LoadBalancersClient Instance
+
+        :type: :class:`LoadBalancersClient <hcloud.load_balancers.client.LoadBalancersClient>`
+        """
+
+        self.load_balancer_types = LoadBalancerTypesClient(self)
+        """LoadBalancerTypesClient Instance
+
+        :type: :class:`LoadBalancerTypesClient <hcloud.load_balancer_types.client.LoadBalancerTypesClient>`
+        """
+
+        self.firewalls = FirewallsClient(self)
+        """FirewallsClient Instance
+
+        :type: :class:`FirewallsClient <hcloud.firewalls.client.FirewallsClient>`
+        """
+
+        self.placement_groups = PlacementGroupsClient(self)
+        """PlacementGroupsClient Instance
+
+        :type: :class:`PlacementGroupsClient <hcloud.placement_groups.client.PlacementGroupsClient>`
+        """
+
+    def _get_user_agent(self) -> str:
+        """Get the user agent of the hcloud-python instance with the user application name (if specified)
+
+        :return: The user agent of this hcloud-python instance
+        """
+        user_agents = []
+        for name, version in [
+            (self._application_name, self._application_version),
+            (self.__user_agent_prefix, self._version),
+        ]:
+            if name is not None:
+                user_agents.append(name if version is None else f"{name}/{version}")
+
+        return " ".join(user_agents)
+
+    def _get_headers(self) -> dict:
+        headers = {
+            "User-Agent": self._get_user_agent(),
+            "Authorization": f"Bearer {self.token}",
+        }
+        return headers
+
+    def _raise_exception_from_response(self, response: requests.Response):
+        raise APIException(
+            code=response.status_code,
+            message=response.reason,
+            details={"content": response.content},
+        )
+
+    def _raise_exception_from_content(self, content: dict):
+        raise APIException(
+            code=content["error"]["code"],
+            message=content["error"]["message"],
+            details=content["error"]["details"],
+        )
+
+    def request(
+        self,
+        method: str,
+        url: str,
+        tries: int = 1,
+        **kwargs,
+    ) -> Union[bytes, dict]:
+        """Perform a request to the Hetzner Cloud API, wrapper around requests.request
+
+        :param method: HTTP Method to perform the Request
+        :param url: URL of the Endpoint
+        :param tries: Tries of the request (used internally, should not be set by the user)
+        :return: Response
+        """
+        response = self._requests_session.request(
+            method=method,
+            url=self._api_endpoint + url,
+            headers=self._get_headers(),
+            **kwargs,
+        )
+
+        content = response.content
+        try:
+            if len(content) > 0:
+                content = response.json()
+        except (TypeError, ValueError):
+            self._raise_exception_from_response(response)
+
+        if not response.ok:
+            if content:
+                if content["error"]["code"] == "rate_limit_exceeded" and tries < 5:
+                    time.sleep(tries * self._retry_wait_time)
+                    tries = tries + 1
+                    return self.request(method, url, tries, **kwargs)
+                else:
+                    self._raise_exception_from_content(content)
+            else:
+                self._raise_exception_from_response(response)
+
+        return content
diff --git a/hcloud/_exceptions.py b/hcloud/_exceptions.py
index 36fee5deeda740b1df1dd706e5d87a25731fd253..d0801e951b0fa470e1edd54a9c2082f323862e27 100644
--- a/hcloud/_exceptions.py
+++ b/hcloud/_exceptions.py
@@ -6,9 +6,7 @@ class APIException(HCloudException):
     """There was an error while performing an API Request"""
 
     def __init__(self, code, message, details):
+        super().__init__(message)
         self.code = code
         self.message = message
         self.details = details
-
-    def __str__(self):
-        return self.message
diff --git a/hcloud/actions/domain.py b/hcloud/actions/domain.py
index 0d91eaca1c1ee1441e75d9bac6c4c8153d2b653d..1cc25d475e4087770b828c3e4af909f53771ecf7 100644
--- a/hcloud/actions/domain.py
+++ b/hcloud/actions/domain.py
@@ -61,12 +61,18 @@ class ActionException(HCloudException):
     """A generic action exception"""
 
     def __init__(self, action):
+        message = self.__doc__
+        if action.error is not None and "message" in action.error:
+            message += f": {action.error['message']}"
+
+        super().__init__(message)
+        self.message = message
         self.action = action
 
 
 class ActionFailedException(ActionException):
-    """The Action you were waiting for failed"""
+    """The pending action failed"""
 
 
 class ActionTimeoutException(ActionException):
-    """The Action you were waiting for timed out"""
+    """The pending action timed out"""
diff --git a/hcloud/hcloud.py b/hcloud/hcloud.py
index e62624f1610bad9a3fd0d015d8403ac7c165e9ce..af4e5c2a51004e51fd139a9b0dde764db2004780 100644
--- a/hcloud/hcloud.py
+++ b/hcloud/hcloud.py
@@ -1,222 +1,9 @@
-import time
-from typing import Optional, Union
+import warnings
 
-import requests
+warnings.warn(
+    "The 'hcloud.hcloud' module is deprecated, please import from the 'hcloud' module instead (e.g. 'from hcloud import Client').",
+    DeprecationWarning,
+    stacklevel=2,
+)
 
-from .__version__ import VERSION
-from ._exceptions import APIException
-from .actions.client import ActionsClient
-from .certificates.client import CertificatesClient
-from .datacenters.client import DatacentersClient
-from .firewalls.client import FirewallsClient
-from .floating_ips.client import FloatingIPsClient
-from .images.client import ImagesClient
-from .isos.client import IsosClient
-from .load_balancer_types.client import LoadBalancerTypesClient
-from .load_balancers.client import LoadBalancersClient
-from .locations.client import LocationsClient
-from .networks.client import NetworksClient
-from .placement_groups.client import PlacementGroupsClient
-from .primary_ips.client import PrimaryIPsClient
-from .server_types.client import ServerTypesClient
-from .servers.client import ServersClient
-from .ssh_keys.client import SSHKeysClient
-from .volumes.client import VolumesClient
-
-
-class Client:
-    """Base Client for accessing the Hetzner Cloud API"""
-
-    _version = VERSION
-    _retry_wait_time = 0.5
-    __user_agent_prefix = "hcloud-python"
-
-    def __init__(
-        self,
-        token: str,
-        api_endpoint: str = "https://api.hetzner.cloud/v1",
-        application_name: Optional[str] = None,
-        application_version: Optional[str] = None,
-        poll_interval: int = 1,
-    ):
-        """Create an new Client instance
-
-        :param token: Hetzner Cloud API token
-        :param api_endpoint: Hetzner Cloud API endpoint
-        :param application_name: Your application name
-        :param application_version: Your application _version
-        :param poll_interval: Interval for polling information from Hetzner Cloud API in seconds
-        """
-        self.token = token
-        self._api_endpoint = api_endpoint
-        self._application_name = application_name
-        self._application_version = application_version
-        self._requests_session = requests.Session()
-        self.poll_interval = poll_interval
-
-        self.datacenters = DatacentersClient(self)
-        """DatacentersClient Instance
-
-        :type: :class:`DatacentersClient <hcloud.datacenters.client.DatacentersClient>`
-        """
-        self.locations = LocationsClient(self)
-        """LocationsClient Instance
-
-        :type: :class:`LocationsClient <hcloud.locations.client.LocationsClient>`
-        """
-        self.servers = ServersClient(self)
-        """ServersClient Instance
-
-        :type: :class:`ServersClient <hcloud.servers.client.ServersClient>`
-        """
-        self.server_types = ServerTypesClient(self)
-        """ServerTypesClient Instance
-
-        :type: :class:`ServerTypesClient <hcloud.server_types.client.ServerTypesClient>`
-        """
-        self.volumes = VolumesClient(self)
-        """VolumesClient Instance
-
-        :type: :class:`VolumesClient <hcloud.volumes.client.VolumesClient>`
-        """
-        self.actions = ActionsClient(self)
-        """ActionsClient Instance
-
-        :type: :class:`ActionsClient <hcloud.actions.client.ActionsClient>`
-        """
-        self.images = ImagesClient(self)
-        """ImagesClient Instance
-
-        :type: :class:`ImagesClient <hcloud.images.client.ImagesClient>`
-        """
-        self.isos = IsosClient(self)
-        """ImagesClient Instance
-
-        :type: :class:`IsosClient <hcloud.isos.client.IsosClient>`
-        """
-        self.ssh_keys = SSHKeysClient(self)
-        """SSHKeysClient Instance
-
-        :type: :class:`SSHKeysClient <hcloud.ssh_keys.client.SSHKeysClient>`
-        """
-        self.floating_ips = FloatingIPsClient(self)
-        """FloatingIPsClient Instance
-
-        :type: :class:`FloatingIPsClient <hcloud.floating_ips.client.FloatingIPsClient>`
-        """
-        self.primary_ips = PrimaryIPsClient(self)
-        """PrimaryIPsClient Instance
-
-        :type: :class:`PrimaryIPsClient <hcloud.primary_ips.client.PrimaryIPsClient>`
-        """
-        self.networks = NetworksClient(self)
-        """NetworksClient Instance
-
-        :type: :class:`NetworksClient <hcloud.networks.client.NetworksClient>`
-        """
-        self.certificates = CertificatesClient(self)
-        """CertificatesClient Instance
-
-        :type: :class:`CertificatesClient <hcloud.certificates.client.CertificatesClient>`
-        """
-
-        self.load_balancers = LoadBalancersClient(self)
-        """LoadBalancersClient Instance
-
-        :type: :class:`LoadBalancersClient <hcloud.load_balancers.client.LoadBalancersClient>`
-        """
-
-        self.load_balancer_types = LoadBalancerTypesClient(self)
-        """LoadBalancerTypesClient Instance
-
-        :type: :class:`LoadBalancerTypesClient <hcloud.load_balancer_types.client.LoadBalancerTypesClient>`
-        """
-
-        self.firewalls = FirewallsClient(self)
-        """FirewallsClient Instance
-
-        :type: :class:`FirewallsClient <hcloud.firewalls.client.FirewallsClient>`
-        """
-
-        self.placement_groups = PlacementGroupsClient(self)
-        """PlacementGroupsClient Instance
-
-        :type: :class:`PlacementGroupsClient <hcloud.placement_groups.client.PlacementGroupsClient>`
-        """
-
-    def _get_user_agent(self) -> str:
-        """Get the user agent of the hcloud-python instance with the user application name (if specified)
-
-        :return: The user agent of this hcloud-python instance
-        """
-        user_agents = []
-        for name, version in [
-            (self._application_name, self._application_version),
-            (self.__user_agent_prefix, self._version),
-        ]:
-            if name is not None:
-                user_agents.append(name if version is None else f"{name}/{version}")
-
-        return " ".join(user_agents)
-
-    def _get_headers(self) -> dict:
-        headers = {
-            "User-Agent": self._get_user_agent(),
-            "Authorization": f"Bearer {self.token}",
-        }
-        return headers
-
-    def _raise_exception_from_response(self, response: requests.Response):
-        raise APIException(
-            code=response.status_code,
-            message=response.reason,
-            details={"content": response.content},
-        )
-
-    def _raise_exception_from_content(self, content: dict):
-        raise APIException(
-            code=content["error"]["code"],
-            message=content["error"]["message"],
-            details=content["error"]["details"],
-        )
-
-    def request(
-        self,
-        method: str,
-        url: str,
-        tries: int = 1,
-        **kwargs,
-    ) -> Union[bytes, dict]:
-        """Perform a request to the Hetzner Cloud API, wrapper around requests.request
-
-        :param method: HTTP Method to perform the Request
-        :param url: URL of the Endpoint
-        :param tries: Tries of the request (used internally, should not be set by the user)
-        :return: Response
-        """
-        response = self._requests_session.request(
-            method=method,
-            url=self._api_endpoint + url,
-            headers=self._get_headers(),
-            **kwargs,
-        )
-
-        content = response.content
-        try:
-            if len(content) > 0:
-                content = response.json()
-        except (TypeError, ValueError):
-            self._raise_exception_from_response(response)
-
-        if not response.ok:
-            if content:
-                if content["error"]["code"] == "rate_limit_exceeded" and tries < 5:
-                    time.sleep(tries * self._retry_wait_time)
-                    tries = tries + 1
-                    return self.request(method, url, tries, **kwargs)
-                else:
-                    self._raise_exception_from_content(content)
-            else:
-                self._raise_exception_from_response(response)
-
-        return content
+from ._client import *  # noqa
diff --git a/tests/unit/actions/test_domain.py b/tests/unit/actions/test_domain.py
index 02959da7eacaf80fdd6f2bed773f67a16f700008..54b730c79800caaa66963eb1484d209beb0229f3 100644
--- a/tests/unit/actions/test_domain.py
+++ b/tests/unit/actions/test_domain.py
@@ -1,7 +1,14 @@
 import datetime
 from datetime import timezone
 
-from hcloud.actions.domain import Action
+import pytest
+
+from hcloud.actions.domain import (
+    Action,
+    ActionException,
+    ActionFailedException,
+    ActionTimeoutException,
+)
 
 
 class TestAction:
@@ -15,3 +22,43 @@ class TestAction:
         assert action.finished == datetime.datetime(
             2016, 3, 30, 23, 50, tzinfo=timezone.utc
         )
+
+
+def test_action_exceptions():
+    with pytest.raises(
+        ActionException,
+        match=r"The pending action failed: Server does not exist anymore",
+    ):
+        raise ActionFailedException(
+            action=Action(
+                **{
+                    "id": 1084730887,
+                    "command": "change_server_type",
+                    "status": "error",
+                    "progress": 100,
+                    "resources": [{"id": 34574042, "type": "server"}],
+                    "error": {
+                        "code": "server_does_not_exist_anymore",
+                        "message": "Server does not exist anymore",
+                    },
+                    "started": "2023-07-06T14:52:42+00:00",
+                    "finished": "2023-07-06T14:53:08+00:00",
+                }
+            )
+        )
+
+    with pytest.raises(ActionException, match=r"The pending action timed out"):
+        raise ActionTimeoutException(
+            action=Action(
+                **{
+                    "id": 1084659545,
+                    "command": "create_server",
+                    "status": "running",
+                    "progress": 50,
+                    "started": "2023-07-06T13:58:38+00:00",
+                    "finished": None,
+                    "resources": [{"id": 34572291, "type": "server"}],
+                    "error": None,
+                }
+            )
+        )
diff --git a/tests/unit/conftest.py b/tests/unit/conftest.py
index d15d36b5223e49d1b4bbf59038988f365f954a9a..0ab7490608c026420fe58ac904914db2fbeeab2c 100644
--- a/tests/unit/conftest.py
+++ b/tests/unit/conftest.py
@@ -7,7 +7,7 @@ from hcloud import Client
 
 @pytest.fixture(autouse=True, scope="function")
 def mocked_requests():
-    patcher = mock.patch("hcloud.hcloud.requests")
+    patcher = mock.patch("hcloud._client.requests")
     mocked_requests = patcher.start()
     yield mocked_requests
     patcher.stop()
diff --git a/tests/unit/test_client.py b/tests/unit/test_client.py
new file mode 100644
index 0000000000000000000000000000000000000000..5f5bf8114b57be52a2bb33f142a0a7bc40adbd68
--- /dev/null
+++ b/tests/unit/test_client.py
@@ -0,0 +1,182 @@
+import json
+from unittest.mock import MagicMock
+
+import pytest
+import requests
+
+from hcloud import APIException, Client
+
+
+class TestHetznerClient:
+    @pytest.fixture()
+    def client(self):
+        Client._version = "0.0.0"
+        client = Client(token="project_token")
+
+        client._requests_session = MagicMock()
+        return client
+
+    @pytest.fixture()
+    def response(self):
+        response = requests.Response()
+        response.status_code = 200
+        response._content = json.dumps({"result": "data"}).encode("utf-8")
+        return response
+
+    @pytest.fixture()
+    def fail_response(self, response):
+        response.status_code = 422
+        error = {
+            "code": "invalid_input",
+            "message": "invalid input in field 'broken_field': is too long",
+            "details": {
+                "fields": [{"name": "broken_field", "messages": ["is too long"]}]
+            },
+        }
+        response._content = json.dumps({"error": error}).encode("utf-8")
+        return response
+
+    @pytest.fixture()
+    def rate_limit_response(self, response):
+        response.status_code = 422
+        error = {
+            "code": "rate_limit_exceeded",
+            "message": "limit of 10 requests per hour reached",
+            "details": {},
+        }
+        response._content = json.dumps({"error": error}).encode("utf-8")
+        return response
+
+    def test__get_user_agent(self, client):
+        user_agent = client._get_user_agent()
+        assert user_agent == "hcloud-python/0.0.0"
+
+    def test__get_user_agent_with_application_name(self, client):
+        client = Client(token="project_token", application_name="my-app")
+        user_agent = client._get_user_agent()
+        assert user_agent == "my-app hcloud-python/0.0.0"
+
+    def test__get_user_agent_with_application_name_and_version(self, client):
+        client = Client(
+            token="project_token",
+            application_name="my-app",
+            application_version="1.0.0",
+        )
+        user_agent = client._get_user_agent()
+        assert user_agent == "my-app/1.0.0 hcloud-python/0.0.0"
+
+    def test__get_headers(self, client):
+        headers = client._get_headers()
+        assert headers == {
+            "User-Agent": "hcloud-python/0.0.0",
+            "Authorization": "Bearer project_token",
+        }
+
+    def test_request_library_mocked(self, client):
+        response = client.request("POST", "url", params={"1": 2})
+        assert response.__class__.__name__ == "MagicMock"
+
+    def test_request_ok(self, client, response):
+        client._requests_session.request.return_value = response
+        response = client.request(
+            "POST", "/servers", params={"argument": "value"}, timeout=2
+        )
+        client._requests_session.request.assert_called_once_with(
+            method="POST",
+            url="https://api.hetzner.cloud/v1/servers",
+            headers={
+                "User-Agent": "hcloud-python/0.0.0",
+                "Authorization": "Bearer project_token",
+            },
+            params={"argument": "value"},
+            timeout=2,
+        )
+        assert response == {"result": "data"}
+
+    def test_request_fails(self, client, fail_response):
+        client._requests_session.request.return_value = fail_response
+        with pytest.raises(APIException) as exception_info:
+            client.request(
+                "POST", "http://url.com", params={"argument": "value"}, timeout=2
+            )
+        error = exception_info.value
+        assert error.code == "invalid_input"
+        assert error.message == "invalid input in field 'broken_field': is too long"
+        assert error.details["fields"][0]["name"] == "broken_field"
+
+    def test_request_500(self, client, fail_response):
+        fail_response.status_code = 500
+        fail_response.reason = "Internal Server Error"
+        fail_response._content = "Internal Server Error"
+        client._requests_session.request.return_value = fail_response
+        with pytest.raises(APIException) as exception_info:
+            client.request(
+                "POST", "http://url.com", params={"argument": "value"}, timeout=2
+            )
+        error = exception_info.value
+        assert error.code == 500
+        assert error.message == "Internal Server Error"
+        assert error.details["content"] == "Internal Server Error"
+
+    def test_request_broken_json_200(self, client, response):
+        content = b"{'key': 'value'"
+        response.reason = "OK"
+        response._content = content
+        client._requests_session.request.return_value = response
+        with pytest.raises(APIException) as exception_info:
+            client.request(
+                "POST", "http://url.com", params={"argument": "value"}, timeout=2
+            )
+        error = exception_info.value
+        assert error.code == 200
+        assert error.message == "OK"
+        assert error.details["content"] == content
+
+    def test_request_empty_content_200(self, client, response):
+        content = ""
+        response.reason = "OK"
+        response._content = content
+        client._requests_session.request.return_value = response
+        response = client.request(
+            "POST", "http://url.com", params={"argument": "value"}, timeout=2
+        )
+        assert response == ""
+
+    def test_request_500_empty_content(self, client, fail_response):
+        fail_response.status_code = 500
+        fail_response.reason = "Internal Server Error"
+        fail_response._content = ""
+        client._requests_session.request.return_value = fail_response
+        with pytest.raises(APIException) as exception_info:
+            client.request(
+                "POST", "http://url.com", params={"argument": "value"}, timeout=2
+            )
+        error = exception_info.value
+        assert error.code == 500
+        assert error.message == "Internal Server Error"
+        assert error.details["content"] == ""
+        assert str(error) == "Internal Server Error"
+
+    def test_request_limit(self, client, rate_limit_response):
+        client._retry_wait_time = 0
+        client._requests_session.request.return_value = rate_limit_response
+        with pytest.raises(APIException) as exception_info:
+            client.request(
+                "POST", "http://url.com", params={"argument": "value"}, timeout=2
+            )
+        error = exception_info.value
+        assert client._requests_session.request.call_count == 5
+        assert error.code == "rate_limit_exceeded"
+        assert error.message == "limit of 10 requests per hour reached"
+
+    def test_request_limit_then_success(self, client, rate_limit_response):
+        client._retry_wait_time = 0
+        response = requests.Response()
+        response.status_code = 200
+        response._content = json.dumps({"result": "data"}).encode("utf-8")
+        client._requests_session.request.side_effect = [rate_limit_response, response]
+
+        client.request(
+            "POST", "http://url.com", params={"argument": "value"}, timeout=2
+        )
+        assert client._requests_session.request.call_count == 2
diff --git a/tests/unit/test_hcloud.py b/tests/unit/test_hcloud.py
index 5f5bf8114b57be52a2bb33f142a0a7bc40adbd68..87ab50aa9d8e905d37f3c183ee3e099610dcef51 100644
--- a/tests/unit/test_hcloud.py
+++ b/tests/unit/test_hcloud.py
@@ -1,182 +1,6 @@
-import json
-from unittest.mock import MagicMock
-
 import pytest
-import requests
-
-from hcloud import APIException, Client
-
-
-class TestHetznerClient:
-    @pytest.fixture()
-    def client(self):
-        Client._version = "0.0.0"
-        client = Client(token="project_token")
-
-        client._requests_session = MagicMock()
-        return client
-
-    @pytest.fixture()
-    def response(self):
-        response = requests.Response()
-        response.status_code = 200
-        response._content = json.dumps({"result": "data"}).encode("utf-8")
-        return response
-
-    @pytest.fixture()
-    def fail_response(self, response):
-        response.status_code = 422
-        error = {
-            "code": "invalid_input",
-            "message": "invalid input in field 'broken_field': is too long",
-            "details": {
-                "fields": [{"name": "broken_field", "messages": ["is too long"]}]
-            },
-        }
-        response._content = json.dumps({"error": error}).encode("utf-8")
-        return response
-
-    @pytest.fixture()
-    def rate_limit_response(self, response):
-        response.status_code = 422
-        error = {
-            "code": "rate_limit_exceeded",
-            "message": "limit of 10 requests per hour reached",
-            "details": {},
-        }
-        response._content = json.dumps({"error": error}).encode("utf-8")
-        return response
-
-    def test__get_user_agent(self, client):
-        user_agent = client._get_user_agent()
-        assert user_agent == "hcloud-python/0.0.0"
-
-    def test__get_user_agent_with_application_name(self, client):
-        client = Client(token="project_token", application_name="my-app")
-        user_agent = client._get_user_agent()
-        assert user_agent == "my-app hcloud-python/0.0.0"
-
-    def test__get_user_agent_with_application_name_and_version(self, client):
-        client = Client(
-            token="project_token",
-            application_name="my-app",
-            application_version="1.0.0",
-        )
-        user_agent = client._get_user_agent()
-        assert user_agent == "my-app/1.0.0 hcloud-python/0.0.0"
-
-    def test__get_headers(self, client):
-        headers = client._get_headers()
-        assert headers == {
-            "User-Agent": "hcloud-python/0.0.0",
-            "Authorization": "Bearer project_token",
-        }
-
-    def test_request_library_mocked(self, client):
-        response = client.request("POST", "url", params={"1": 2})
-        assert response.__class__.__name__ == "MagicMock"
-
-    def test_request_ok(self, client, response):
-        client._requests_session.request.return_value = response
-        response = client.request(
-            "POST", "/servers", params={"argument": "value"}, timeout=2
-        )
-        client._requests_session.request.assert_called_once_with(
-            method="POST",
-            url="https://api.hetzner.cloud/v1/servers",
-            headers={
-                "User-Agent": "hcloud-python/0.0.0",
-                "Authorization": "Bearer project_token",
-            },
-            params={"argument": "value"},
-            timeout=2,
-        )
-        assert response == {"result": "data"}
-
-    def test_request_fails(self, client, fail_response):
-        client._requests_session.request.return_value = fail_response
-        with pytest.raises(APIException) as exception_info:
-            client.request(
-                "POST", "http://url.com", params={"argument": "value"}, timeout=2
-            )
-        error = exception_info.value
-        assert error.code == "invalid_input"
-        assert error.message == "invalid input in field 'broken_field': is too long"
-        assert error.details["fields"][0]["name"] == "broken_field"
-
-    def test_request_500(self, client, fail_response):
-        fail_response.status_code = 500
-        fail_response.reason = "Internal Server Error"
-        fail_response._content = "Internal Server Error"
-        client._requests_session.request.return_value = fail_response
-        with pytest.raises(APIException) as exception_info:
-            client.request(
-                "POST", "http://url.com", params={"argument": "value"}, timeout=2
-            )
-        error = exception_info.value
-        assert error.code == 500
-        assert error.message == "Internal Server Error"
-        assert error.details["content"] == "Internal Server Error"
-
-    def test_request_broken_json_200(self, client, response):
-        content = b"{'key': 'value'"
-        response.reason = "OK"
-        response._content = content
-        client._requests_session.request.return_value = response
-        with pytest.raises(APIException) as exception_info:
-            client.request(
-                "POST", "http://url.com", params={"argument": "value"}, timeout=2
-            )
-        error = exception_info.value
-        assert error.code == 200
-        assert error.message == "OK"
-        assert error.details["content"] == content
-
-    def test_request_empty_content_200(self, client, response):
-        content = ""
-        response.reason = "OK"
-        response._content = content
-        client._requests_session.request.return_value = response
-        response = client.request(
-            "POST", "http://url.com", params={"argument": "value"}, timeout=2
-        )
-        assert response == ""
-
-    def test_request_500_empty_content(self, client, fail_response):
-        fail_response.status_code = 500
-        fail_response.reason = "Internal Server Error"
-        fail_response._content = ""
-        client._requests_session.request.return_value = fail_response
-        with pytest.raises(APIException) as exception_info:
-            client.request(
-                "POST", "http://url.com", params={"argument": "value"}, timeout=2
-            )
-        error = exception_info.value
-        assert error.code == 500
-        assert error.message == "Internal Server Error"
-        assert error.details["content"] == ""
-        assert str(error) == "Internal Server Error"
-
-    def test_request_limit(self, client, rate_limit_response):
-        client._retry_wait_time = 0
-        client._requests_session.request.return_value = rate_limit_response
-        with pytest.raises(APIException) as exception_info:
-            client.request(
-                "POST", "http://url.com", params={"argument": "value"}, timeout=2
-            )
-        error = exception_info.value
-        assert client._requests_session.request.call_count == 5
-        assert error.code == "rate_limit_exceeded"
-        assert error.message == "limit of 10 requests per hour reached"
 
-    def test_request_limit_then_success(self, client, rate_limit_response):
-        client._retry_wait_time = 0
-        response = requests.Response()
-        response.status_code = 200
-        response._content = json.dumps({"result": "data"}).encode("utf-8")
-        client._requests_session.request.side_effect = [rate_limit_response, response]
 
-        client.request(
-            "POST", "http://url.com", params={"argument": "value"}, timeout=2
-        )
-        assert client._requests_session.request.call_count == 2
+def test_deprecated_hcloud_hcloud_module():
+    with pytest.deprecated_call():
+        from hcloud.hcloud import Client  # noqa