diff --git a/duniterpy/api/ws2p/__init__.py b/duniterpy/api/ws2p/__init__.py
index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..2fac55f9b786a25b93e614276e335fa5aec68edd 100644
--- a/duniterpy/api/ws2p/__init__.py
+++ b/duniterpy/api/ws2p/__init__.py
@@ -0,0 +1,3 @@
+from . import network
+
+
diff --git a/duniterpy/api/ws2p/network.py b/duniterpy/api/ws2p/network.py
index 14b331c53ced6cd584bd7f873f7502ad6c9c89d1..a5c37808c0d5b9d9961ac4cb1bcddebf3305d3c7 100644
--- a/duniterpy/api/ws2p/network.py
+++ b/duniterpy/api/ws2p/network.py
@@ -14,55 +14,52 @@
 #
 # Authors:
 # Caner Candan <caner@candan.fr>, http://caner.candan.fr
-#
+# vit
+import logging
 
-from duniterpy.api.client import API, logging, parse_response
+from duniterpy.api.client import Client
 
 logger = logging.getLogger("duniter/network")
 
-URL_PATH = 'network'
+MODULE = 'network'
 
 WS2P_HEADS_SCHEMA = {
-                    "type": "object",
-                    "properties": {
-                        "heads": {
-                            "type": "array",
-                            "items": {
-                                "type": "object",
-                                "properties": {
-                                    "message": {
-                                        "type": "string"
-                                    },
-                                    "sig": {
-                                        "type": "string",
-                                    },
-                                    "messageV2": {
-                                        "type": "string"
-                                    },
-                                    "sigV2": {
-                                        "type": "string",
-                                    },
-                                    "step": {
-                                        "type": "number",
-                                    },
-                                },
-                                "required": ["message", "sig"]
-                            }
-                        }
+    "type": "object",
+    "properties": {
+        "heads": {
+            "type": "array",
+            "items": {
+                "type": "object",
+                "properties": {
+                    "message": {
+                        "type": "string"
+                    },
+                    "sig": {
+                        "type": "string",
+                    },
+                    "messageV2": {
+                        "type": "string"
+                    },
+                    "sigV2": {
+                        "type": "string",
                     },
-                    "required": ["heads"]
-                }
+                    "step": {
+                        "type": "number",
+                    },
+                },
+                "required": ["message", "sig"]
+            }
+        }
+    },
+    "required": ["heads"]
+}
 
 
-async def heads(connection):
+def heads(client: Client):
     """
     GET Certification data over a member
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
+    :param client: Client to connect to the api
     :rtype: dict
     """
-
-    client = API(connection, URL_PATH)
-
-    r = await client.requests_get('/ws2p/heads')
-    return await parse_response(r, WS2P_HEADS_SCHEMA)
+    return client.connect_ws(MODULE + '/ws2p/heads')
diff --git a/examples/request_ws2p.py b/examples/request_ws2p.py
new file mode 100644
index 0000000000000000000000000000000000000000..095215d124b3e23222e772fa93134a19d298e298
--- /dev/null
+++ b/examples/request_ws2p.py
@@ -0,0 +1,73 @@
+import asyncio
+from _socket import gaierror
+
+import aiohttp
+import jsonschema
+
+from duniterpy.api.client import Client, parse_text
+from duniterpy.api import ws2p
+
+# CONFIG #######################################
+
+# You can either use a complete defined endpoint : [NAME_OF_THE_API] [DOMAIN] [IPv4] [IPv6] [PORT]
+# or the simple definition : [NAME_OF_THE_API] [DOMAIN] [PORT]
+# Here we use the secure BASIC_MERKLED_API (BMAS)
+WS2P_ENDPOINT = "WS2P id ip port"
+
+################################################
+
+
+async def main():
+    """
+    Main code (synchronous requests)
+    """
+    # Create Client from endpoint string in Duniter format
+    client = Client(WS2P_ENDPOINT)
+
+    # Get the node summary infos by dedicated method (with json schema validation)
+    print("\nCall ws2p.heads:")
+    try:
+        # Create Web Socket connection on block path
+        ws_connection = client(ws2p.network.heads)
+
+        # From the documentation ws_connection should be a ClientWebSocketResponse object...
+        #
+        # https://docs.aiohttp.org/en/stable/client_quickstart.html#websockets
+        #
+        # In reality, aiohttp.session.ws_connect() returns a aiohttp.client._WSRequestContextManager instance.
+        # It must be used in a with statement to get the ClientWebSocketResponse instance from it (__aenter__).
+        # At the end of the with statement, aiohttp.client._WSRequestContextManager.__aexit__ is called
+        # and close the ClientWebSocketResponse in it.
+
+        # Mandatory to get the "for msg in ws" to work !
+        async with ws_connection as ws:
+            print("Connected successfully to web socket block path")
+            # Iterate on each message received...
+            async for msg in ws:
+                # if message type is text...
+                if msg.type == aiohttp.WSMsgType.TEXT:
+                    print("Received a block")
+                    # Validate jsonschema and return a the json dict
+                    block_data = parse_text(msg.data, ws2p.network.WS2P_HEADS_SCHEMA)
+                    print(block_data)
+                elif msg.type == aiohttp.WSMsgType.CLOSED:
+                    # Connection is closed
+                    print("Web socket connection closed !")
+                elif msg.type == aiohttp.WSMsgType.ERROR:
+                    # Connection error
+                    print("Web socket connection error !")
+
+                # Close session
+                await client.close()
+
+    except (aiohttp.WSServerHandshakeError, ValueError) as e:
+        print("Websocket block {0} : {1}".format(type(e).__name__, str(e)))
+    except (aiohttp.ClientError, gaierror, TimeoutError) as e:
+        print("{0} : {1}".format(str(e), WS2P_ENDPOINT))
+    except jsonschema.ValidationError as e:
+        print("{:}:{:}".format(str(e.__class__.__name__), str(e)))
+
+
+# Latest duniter-python-api is asynchronous and you have to use asyncio, an asyncio loop and a "as" on the data.
+# ( https://docs.python.org/3/library/asyncio.html )
+asyncio.get_event_loop().run_until_complete(main())
diff --git a/tests/api/test_bma.py b/tests/api/bma/test_bma.py
similarity index 100%
rename from tests/api/test_bma.py
rename to tests/api/bma/test_bma.py
diff --git a/tests/api/bma/test_ws2p.py b/tests/api/bma/test_ws2p.py
deleted file mode 100644
index 1e4c9e817ebb3fa9de26d57ec58a0b49ab32d5fa..0000000000000000000000000000000000000000
--- a/tests/api/bma/test_ws2p.py
+++ /dev/null
@@ -1,54 +0,0 @@
-import unittest
-import aiohttp
-import jsonschema
-import json
-from duniterpy.documents import BMAEndpoint
-from tests.api.webserver import WebFunctionalSetupMixin, web, asyncio
-from duniterpy.api.bma.network import heads, WS2P_HEADS_SCHEMA
-from duniterpy.api.bma import parse_text
-
-
-class Test_WS2P_Heads(WebFunctionalSetupMixin, unittest.TestCase):
-
-    def test_block(self):
-        json_sample = {
-  "heads": [
-    {
-      "message": "WS2POCAIC:HEAD:1:8iVdpXqFLCxGyPqgVx5YbFSkmWKkceXveRd2yvBKeARL:102102-000002C0694C7D373A78B095419C86584B81804CFB9641B7EBC3A18040B6FEE6:e66254bf:duniter:1.6.20:1",
-      "sig": "ZO5gSUMK6IaUEwU4K40nhuHOfnJ6Zfn8VS+4Ko2FM7t+mDsHf+3gDRT9PgV2p0fz81mF6jVYWpq2UYEsnK/gCg==",
-      "messageV2": "WS2POCAIC:HEAD:2:8iVdpXqFLCxGyPqgVx5YbFSkmWKkceXveRd2yvBKeARL:102102-000002C0694C7D373A78B095419C86584B81804CFB9641B7EBC3A18040B6FEE6:e66254bf:duniter:1.6.20:1:15:14",
-      "sigV2": "ReXzbgUya9jo4dL/R4g19Y+RE9BGB0xDkw7mrBWoldlRLkq3KFyRkAf9VthVx1UUb/AINr3nxImZKVQiVH9+DQ==",
-      "step": 0
-    },
-    {
-      "message": "WS2POCAIC:HEAD:1:2ny7YAdmzReQxAayyJZsyVYwYhVyax2thKcGknmQy5nQ:102102-000002C0694C7D373A78B095419C86584B81804CFB9641B7EBC3A18040B6FEE6:a0a45ed2:duniter:1.6.21:1",
-      "sig": "pXLMmOpyEMdWihT183g/rnCvMzA2gHki5Cxg7rEl3psQu0RuK0ObCv5YFhmQnRlg+QZ1CWfbYEEbm3G1eGplAQ==",
-      "messageV2": "WS2POCAIC:HEAD:2:2ny7YAdmzReQxAayyJZsyVYwYhVyax2thKcGknmQy5nQ:102102-000002C0694C7D373A78B095419C86584B81804CFB9641B7EBC3A18040B6FEE6:a0a45ed2:duniter:1.6.21:1:34:28",
-      "sigV2": "p5f7/KfQqjTaCYSMUXpjUDH7uF2DafetHNgphGzkOXgxM+Upeii0Fz2RFBwnZvN+Gjp81hAqSuH48PJP6HJSAw==",
-      "step": 1
-    },
-    {
-      "message": "WS2POCA:HEAD:1:GRBPV3Y7PQnB9LaZhSGuS3BqBJbSHyibzYq65kTh1nQ4:102102-000002C0694C7D373A78B095419C86584B81804CFB9641B7EBC3A18040B6FEE6:6d0e96f9:duniter:1.6.21:1",
-      "sig": "h9o1XBEV18gUzbvj1jdQB1M7U8ifZprIyVwLdlSQEfeG9WZLvZAjYzLGA2nD6h/9RkJLOJPzIQJXysHUHJ2dDQ==",
-      "messageV2": "WS2POCA:HEAD:2:GRBPV3Y7PQnB9LaZhSGuS3BqBJbSHyibzYq65kTh1nQ4:102102-000002C0694C7D373A78B095419C86584B81804CFB9641B7EBC3A18040B6FEE6:6d0e96f9:duniter:1.6.21:1:20:20",
-      "sigV2": "VsyQmXOUYrfHWy0FeS4rJrIJCUBI+3BergbSYQ78icJWV6MQzZSw7Z+Yl7urujCYZriDQM76D6GW+6F0EELpBQ==",
-      "step": 2
-    },
-  ]
-}
-
-        jsonschema.validate(json_sample, WS2P_HEADS_SCHEMA)
-
-    def test_bma_ws2p_heads_bad(self):
-        async def handler(request):
-            await request.read()
-            return web.Response(body=b'{}', content_type='application/json')
-
-        async def go():
-            _, port, url = await self.create_server('GET', '/network/ws2p/heads', handler)
-            with self.assertRaises(jsonschema.ValidationError):
-                async with aiohttp.ClientSession() as session:
-                    connection = BMAEndpoint("127.0.0.1", None, None, port).conn_handler(session)
-                    await heads(connection)
-
-        self.loop.run_until_complete(go())
diff --git a/tests/api/ws2p/__init__.py b/tests/api/ws2p/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/tests/api/ws2p/test_ws2p.py b/tests/api/ws2p/test_ws2p.py
new file mode 100644
index 0000000000000000000000000000000000000000..7c97c720bf16ff7aba5955057fa3e203cf1e4b93
--- /dev/null
+++ b/tests/api/ws2p/test_ws2p.py
@@ -0,0 +1,63 @@
+import unittest
+
+import jsonschema
+
+from duniterpy.api.client import Client
+from duniterpy.api.endpoint import BMAEndpoint
+from duniterpy.api.ws2p.network import heads, WS2P_HEADS_SCHEMA
+from tests.api.webserver import WebFunctionalSetupMixin, web
+
+
+class TestWs2pHeads(WebFunctionalSetupMixin, unittest.TestCase):
+
+    def test_block(self):
+        json_sample = {
+            "heads": [
+                {
+                    "message": "WS2POCAIC:HEAD:1:8iVdpXqFLCxGyPqgVx5YbFSkmWKkceXveRd2yvBKeARL:\
+                    102102-000002C0694C7D373A78B095419C86584B81804CFB9641B7EBC3A18040B6FEE6:e66254bf:duniter:1.6.20:1",
+                    "sig": "ZO5gSUMK6IaUEwU4K40nhuHOfnJ6Zfn8VS+4Ko2FM7t+mDsHf+3gDRT9PgV2p0fz81mF6jVYWpq2UYEsnK/gCg==",
+                    "messageV2": "WS2POCAIC:HEAD:2:8iVdpXqFLCxGyPqgVx5YbFSkmWKkceXveRd2yvBKeARL:\
+                    102102-000002C0694C7D373A78B095419C86584B81804CFB9641B7EBC3A18040B6FEE6:e66254bf:\
+                    duniter:1.6.20:1:15:14",
+                    "sigV2": "ReXzbgUya9jo4dL/R4g19Y+RE9BGB0xDkw7mrBWoldlRLkq3KFyRkAf9VthVx1UUb/AINr3nxImZKVQiVH9+DQ==",
+                    "step": 0
+                },
+                {
+                    "message": "WS2POCAIC:HEAD:1:2ny7YAdmzReQxAayyJZsyVYwYhVyax2thKcGknmQy5nQ:\
+                    102102-000002C0694C7D373A78B095419C86584B81804CFB9641B7EBC3A18040B6FEE6:a0a45ed2:duniter:1.6.21:1",
+                    "sig": "pXLMmOpyEMdWihT183g/rnCvMzA2gHki5Cxg7rEl3psQu0RuK0ObCv5YFhmQnRlg+QZ1CWfbYEEbm3G1eGplAQ==",
+                    "messageV2": "WS2POCAIC:HEAD:2:2ny7YAdmzReQxAayyJZsyVYwYhVyax2thKcGknmQy5nQ:\
+                    102102-000002C0694C7D373A78B095419C86584B81804CFB9641B7EBC3A18040B6FEE6:a0a45ed2:\
+                    duniter:1.6.21:1:34:28",
+                    "sigV2": "p5f7/KfQqjTaCYSMUXpjUDH7uF2DafetHNgphGzkOXgxM+Upeii0Fz2RFBwnZvN+Gjp81hAqSuH48PJP6HJSAw==",
+                    "step": 1
+                },
+                {
+                    "message": "WS2POCA:HEAD:1:GRBPV3Y7PQnB9LaZhSGuS3BqBJbSHyibzYq65kTh1nQ4:\
+                    102102-000002C0694C7D373A78B095419C86584B81804CFB9641B7EBC3A18040B6FEE6:6d0e96f9:duniter:1.6.21:1",
+                    "sig": "h9o1XBEV18gUzbvj1jdQB1M7U8ifZprIyVwLdlSQEfeG9WZLvZAjYzLGA2nD6h/9RkJLOJPzIQJXysHUHJ2dDQ==",
+                    "messageV2": "WS2POCA:HEAD:2:GRBPV3Y7PQnB9LaZhSGuS3BqBJbSHyibzYq65kTh1nQ4:\
+                    102102-000002C0694C7D373A78B095419C86584B81804CFB9641B7EBC3A18040B6FEE6:6d0e96f9:\
+                    duniter:1.6.21:1:20:20",
+                    "sigV2": "VsyQmXOUYrfHWy0FeS4rJrIJCUBI+3BergbSYQ78icJWV6MQzZSw7Z+Yl7urujCYZriDQM76D6GW+6F0EELpBQ==",
+                    "step": 2
+                },
+            ]
+        }
+
+        jsonschema.validate(json_sample, WS2P_HEADS_SCHEMA)
+
+    def test_ws2p_heads_bad(self):
+        async def handler(request):
+            await request.read()
+            return web.Response(body=b'{}', content_type='application/json')
+
+        async def go():
+            _, port, url = await self.create_server('GET', '/network/ws2p/heads', handler)
+            with self.assertRaises(jsonschema.ValidationError):
+                client = Client(BMAEndpoint("127.0.0.1", "", "", port))
+                await client(heads)
+            await client.close()
+
+        self.loop.run_until_complete(go())