diff --git a/duniterpy/api/bma/__init__.py b/duniterpy/api/bma/__init__.py
index 727c52b784cda73e4125b650aca550efc994295d..a1fae4d59a6566eee67a0f6c358ccace21773efc 100644
--- a/duniterpy/api/bma/__init__.py
+++ b/duniterpy/api/bma/__init__.py
@@ -15,16 +15,12 @@
 # Authors:
 # Caner Candan <caner@candan.fr>, http://caner.candan.fr
 # Inso <insomniak.fr at gmail.com>
+import logging
+from . import network, blockchain, tx, wot, node, ud, ws
 
-
-__all__ = ['api']
+__all__ = [network, blockchain, tx, wot, node, ud, ws]
 
 PROTOCOL_VERSION = 2
 
-import logging
-
 logger = logging.getLogger("duniter")
 
-
-from .api import API, ConnectionHandler, parse_error, parse_response, parse_text
-from . import network, blockchain, tx, wot, node, ud, ws
diff --git a/duniterpy/api/bma/blockchain.py b/duniterpy/api/bma/blockchain.py
index a3a6d4bcafedfd08783535042e386a5cf34021f2..a10a6e3ca896099245ab1fe5613bb8a9c5add7e5 100644
--- a/duniterpy/api/bma/blockchain.py
+++ b/duniterpy/api/bma/blockchain.py
@@ -14,13 +14,13 @@
 #
 # Authors:
 # Caner Candan <caner@candan.fr>, http://caner.candan.fr
-#
-
-from duniterpy.api.bma import API, logging, parse_response
+# vit
+import logging
+from duniterpy.api.client import Client
 
 logger = logging.getLogger("duniter/blockchain")
 
-URL_PATH = 'blockchain'
+MODULE = 'blockchain'
 
 BLOCK_SCHEMA = {
     "type": "object",
@@ -235,8 +235,8 @@ PARAMETERS_SCHEMA = {
                   "type": "number"
               }
             },
-        "required": ["currency", "c", "dt", "ud0","sigPeriod", "sigValidity", "sigQty", "xpercent", "sigStock",
-                     "sigWindow", "msValidity","stepMax", "medianTimeBlocks",
+        "required": ["currency", "c", "dt", "ud0", "sigPeriod", "sigValidity", "sigQty", "xpercent", "sigStock",
+                     "sigWindow", "msValidity", "stepMax", "medianTimeBlocks",
                      "avgGenTime", "dtDiffEval", "percentRot", "udTime0", "udReevalTime0", "dtReeval"]
     }
 
@@ -302,196 +302,170 @@ HARDSHIP_SCHEMA = {
 }
 
 
-async def parameters(connection):
+async def parameters(client: Client) -> dict:
     """
     GET the blockchain parameters used by this node
 
-    :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('/parameters')
-    return await parse_response(r, PARAMETERS_SCHEMA)
+    return await client.get(MODULE + '/parameters', schema=PARAMETERS_SCHEMA)
+
 
-async def memberships(connection, search):
+async def memberships(client: Client, search: str) -> dict:
     """
     GET list of Membership documents for UID/Public key
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :param str search: UID/Public key
+    :param client: Client to connect to the api
+    :param search: UID/Public key
     :rtype: dict
     """
-    client = API(connection, URL_PATH)
+    return await client.get(MODULE + '/memberships/%s' % search, schema=MEMBERSHIPS_SCHEMA)
 
-    r = await client.requests_get('/memberships/%s' % search)
-    return await parse_response(r, MEMBERSHIPS_SCHEMA)
 
-async def membership(connection, membership):
+# async def membership(connection, membership):
+#     """
+#     POST a Membership document
+#
+#     :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
+#     :param str membership: Membership signed raw document
+#     :rtype: aiohttp.ClientResponse
+#     """
+#     client = API(connection, MODULE)
+#
+#     return await client.requests_post('/membership', membership=membership)
+
+async def current(client: Client) -> dict:
     """
-    POST a Membership document
+    GET, return last accepted block
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :param str membership: Membership signed raw document
-    :rtype: aiohttp.ClientResponse
+    :param client: Client to connect to the api
+    :rtype: dict
     """
-    client = API(connection, URL_PATH)
+    return await client.get(MODULE + '/current', schema=BLOCK_SCHEMA)
 
-    return await client.requests_post('/membership', membership=membership)
 
-async def block(connection, number=0, block=None, signature=None):
+async def block(client: Client, number: int = 0, _block: dict = None, signature: str = None):
     """
     GET/POST a block from/to the blockchain
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :param int number: Block number to get
-    :param dict block: Block document to post
+    :param client: Client to connect to the api
+    :param number: Block number to get
+    :param dict _block: Block document to post
     :param str signature: Signature of the block document issuer
     :rtype: dict
     """
 
-    client = API(connection, URL_PATH)
-    # POST block
-    if block is not None and signature is not None:
-        return await client.requests_post('/block', block=block, signature=signature)
+    # client = API(connection, MODULE)
+    # # POST block
+    # if _block is not None and signature is not None:
+    #     return await client.requests_post('/block', block=_block, signature=signature)
 
     # GET block
-    r = await client.requests_get('/block/%d' % number)
-    data = await parse_response(r, BLOCK_SCHEMA)
-    return data
-
-async def current(connection):
-    """
-    GET, return last accepted block
+    return await client.get(MODULE + '/block/%d' % number, schema=BLOCK_SCHEMA)
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :rtype: dict
-    """
-
-    client = API(connection, URL_PATH)
 
-    r = await client.requests_get('/current')
-    return await parse_response(r, BLOCK_SCHEMA)
-
-
-async def blocks(connection, count, start):
+async def blocks(client: Client, count: int, start: int) -> list:
     """
     GET list of blocks from the blockchain
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :param int count: Number of blocks
-    :param int start: First block number
+    :param client: Client to connect to the api
+    :param count: Number of blocks
+    :param start: First block number
     :rtype: list
     """
-
-    client = API(connection, URL_PATH)
     assert type(count) is int
     assert type(start) is int
-    r = await client.requests_get('/blocks/%d/%d' % (count, start))
-    return await parse_response(r, BLOCKS_SCHEMA)
 
-async def hardship(connection, pubkey):
+    return await client.get(MODULE + '/blocks/%d/%d' % (count, start), schema=BLOCKS_SCHEMA)
+
+
+async def hardship(client: Client, pubkey: str) -> dict:
     """
     GET hardship level for given member's public key for writing next block
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :param str pubkey:  Public key of the member
+    :param client: Client to connect to the api
+    :param pubkey:  Public key of the member
     :rtype: dict
     """
-    client = API(connection, URL_PATH)
-    r = await client.requests_get('/hardship/%s' % pubkey)
-    return await parse_response(r, HARDSHIP_SCHEMA)
+    return await client.get(MODULE + '/hardship/%s' % pubkey, schema=HARDSHIP_SCHEMA)
+
 
-async def newcomers(connection):
+async def newcomers(client: Client) -> dict:
     """
     GET, return block numbers containing newcomers
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
+    :param client: Client to connect to the api
     :rtype: dict
     """
+    return await client.get(MODULE + '/with/newcomers', schema=BLOCK_NUMBERS_SCHEMA)
 
-    client = API(connection, URL_PATH)
-    r = await client.requests_get('/with/newcomers')
-    return await parse_response(r, BLOCK_NUMBERS_SCHEMA)
 
-async def certifications(connection):
+async def certifications(client: Client) -> dict:
     """
     GET, return block numbers containing certifications
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
+    :param client: Client to connect to the api
     :rtype: dict
     """
+    return await client.get(MODULE + '/with/certs', schema=BLOCK_NUMBERS_SCHEMA)
 
-    client = API(connection, URL_PATH)
-    r = await client.requests_get('/with/certs')
-    return await parse_response(r, BLOCK_NUMBERS_SCHEMA)
 
-async def joiners(connection):
+async def joiners(client: Client) -> dict:
     """
     GET, return block numbers containing joiners
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
+    :param client: Client to connect to the api
     :rtype: dict
     """
+    return await client.get(MODULE + '/with/joiners', schema=BLOCK_NUMBERS_SCHEMA)
 
-    client = API(connection, URL_PATH)
-    r = await client.requests_get('/with/joiners')
-    return await parse_response(r, BLOCK_NUMBERS_SCHEMA)
 
-async def actives(connection):
+async def actives(client: Client) -> dict:
     """
     GET, return block numbers containing actives
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
+    :param client: Client to connect to the api
     :rtype: dict
     """
+    return await client.get(MODULE + '/with/actives', schema=BLOCK_NUMBERS_SCHEMA)
 
-    client = API(connection, URL_PATH)
-    r = await client.requests_get('/with/actives')
-    return await parse_response(r, BLOCK_NUMBERS_SCHEMA)
 
-async def leavers(connection):
+async def leavers(client: Client) -> dict:
     """
     GET, return block numbers containing leavers
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
+    :param client: Client to connect to the api
     :rtype: dict
     """
+    return await client.get(MODULE + '/with/leavers', schema=BLOCK_NUMBERS_SCHEMA)
 
-    client = API(connection, URL_PATH)
-    r = await client.requests_get('/with/leavers')
-    return await parse_response(r, BLOCK_NUMBERS_SCHEMA)
 
-async def excluded(connection):
+async def excluded(client: Client) -> dict:
     """
     GET, return block numbers containing excluded
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
+    :param client: Client to connect to the api
     :rtype: dict
     """
+    return await client.get(MODULE + '/with/excluded', schema=BLOCK_NUMBERS_SCHEMA)
 
-    client = API(connection, URL_PATH)
-    r = await client.requests_get('/with/excluded')
-    return await parse_response(r, BLOCK_NUMBERS_SCHEMA)
 
-async def ud(connection):
+async def ud(client: Client) -> dict:
     """
     GET, return block numbers containing universal dividend
 
-    :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('/with/ud')
-    return await parse_response(r, BLOCK_NUMBERS_SCHEMA)
+    return await client.get(MODULE + '/with/ud', schema=BLOCK_NUMBERS_SCHEMA)
 
-async def tx(connection):
+
+async def tx(client: Client) -> dict:
     """
     GET, return block numbers containing transactions
 
-    :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('/with/tx')
-    return await parse_response(r, BLOCK_NUMBERS_SCHEMA)
+    return await client.get(MODULE + '/with/tx', schema=BLOCK_NUMBERS_SCHEMA)
diff --git a/duniterpy/api/bma/network.py b/duniterpy/api/bma/network.py
index d02b22e1a22c6988c1a286fc265034cbad9d89c1..eedaaecc3b86609ea0a2d70561e114fd53171905 100644
--- a/duniterpy/api/bma/network.py
+++ b/duniterpy/api/bma/network.py
@@ -14,13 +14,14 @@
 #
 # Authors:
 # Caner Candan <caner@candan.fr>, http://caner.candan.fr
-#
-
-from duniterpy.api.bma import API, logging, parse_response
+# vit
+import logging
+from duniterpy.api.client import Client
+from duniterpy.documents.peer import Peer
 
 logger = logging.getLogger("duniter/network")
 
-URL_PATH = 'network'
+MODULE = 'network'
 
 PEERING_SCHEMA = {
         "type": "object",
@@ -100,91 +101,42 @@ PEERS_SCHEMA = schema = {
         ]
     }
 
-async def peering(connection):
+
+async def peering(client: Client) -> dict:
     """
     GET peering information about a peer
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
+    :param client: Client to connect to the api
     :rtype: dict
     """
+    return await client.get(MODULE + '/peering', schema=PEERING_SCHEMA)
 
-    client = API(connection, URL_PATH)
-    r = await client.requests_get('/peering')
-    return await parse_response(r, PEERING_SCHEMA)
 
-async def peers(connection, leaves=False, leaf=""):
+async def peers(client: Client, leaves: bool = False, leaf: str = ""):
     """
     GET peering entries of every node inside the currency network
 
-    :param bool leaves: True if leaves should be requested
-    :param str leaf: True if leaf should be requested
+    :param client: Client to connect to the api
+    :param leaves: True if leaves should be requested
+    :param leaf: True if leaf should be requested
     :rtype: dict
     """
-
-    client = API(connection, URL_PATH)
-    # GET Peers
-    if leaves:
-        r = await client.requests_get('/peering/peers', leaves=leaves)
+    if leaves is True:
+        return await client.get(MODULE + '/peering/peers', {"leaves": "true"}, schema=PEERS_SCHEMA)
     else:
-        r = await client.requests_get('/peering/peers', leaf=leaf)
-
-    return await parse_response(r, PEERS_SCHEMA)
-
-async def peer(connection, entry=None, signature=None):
-    """
-    GET peering entries of every node inside the currency network
-
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :param duniterpy.documents.peer.Peer entry: Peer document
-    :param str signature: Signature of the document issuer
-    :rtype: dict
-    """
+        return await client.get(MODULE + '/peering/peers', {"leaf": leaf}, schema=PEERS_SCHEMA)
 
-    client = API(connection, URL_PATH)
-    r = await client.requests_post('/peering/peers', entry=entry, signature=signature)
-    return r
 
-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"]
-                            }
-                        }
-                    },
-                    "required": ["heads"]
-                }
-
-
-async def heads(connection):
-    """
-    GET Certification data over a member
-
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :rtype: dict
-    """
-
-    client = API(connection, URL_PATH)
-
-    r = await client.requests_get('/ws2p/heads')
-    return await parse_response(r, WS2P_HEADS_SCHEMA)
+# async def peer(client: Client, entry: Peer = None, signature: str = None) -> dict:
+#     """
+#     POST a Peer document with his signature
+#
+#     :param client: Client to connect to the api
+#     :param entry: Peer document
+#     :param signature: Signature of the document issuer
+#     :rtype: dict
+#     """
+#
+#     client = API(connection, MODULE)
+#     r = await client.requests_post('/peering/peers', entry=entry, signature=signature)
+#     return r
diff --git a/duniterpy/api/bma/node.py b/duniterpy/api/bma/node.py
index c6b26411af8b4a047ae0d2fa8e57bad2df77f0bf..b3a630f5c0064865257600358fedfe75f1b8d1e5 100644
--- a/duniterpy/api/bma/node.py
+++ b/duniterpy/api/bma/node.py
@@ -14,19 +14,20 @@
 #
 # Authors:
 # Caner Candan <caner@candan.fr>, http://caner.candan.fr
-#
-
-from duniterpy.api.bma import API, logging, parse_response
+# vit
+import logging
+from duniterpy.api.client import Client
 
 logger = logging.getLogger("duniter/node")
 
-URL_PATH = 'node'
+MODULE = 'node'
+
 
-async def summary(connection):
+async def summary(client: Client) -> dict:
     """
-    GET Certification data over a member
+    GET Duniter node version and infos
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
+    :param client: Client to connect to the api
     :rtype: dict
     """
     schema = {
@@ -36,7 +37,7 @@ async def summary(connection):
                 "type": "object",
                 "properties": {
                     "software": {
-                    "type": "string"
+                        "type": "string"
                     },
                     "version": {
                         "type": "string",
@@ -50,7 +51,5 @@ async def summary(connection):
         },
         "required": ["duniter"]
     }
-    client = API(connection, URL_PATH)
 
-    r = await client.requests_get('/summary')
-    return await parse_response(r, schema)
+    return await client.get(MODULE + '/summary', schema=schema)
diff --git a/duniterpy/api/bma/tx.py b/duniterpy/api/bma/tx.py
index 046c70529ba07554ad2dcf42b63cb866e91a5527..dfeae4170e38cf0e6b1040962380aecc44423abe 100644
--- a/duniterpy/api/bma/tx.py
+++ b/duniterpy/api/bma/tx.py
@@ -14,13 +14,14 @@
 #
 # Authors:
 # Caner Candan <caner@candan.fr>, http://caner.candan.fr
-#
-
-from duniterpy.api.bma import API, logging, parse_response
+# vit
+import logging
+from duniterpy.api.client import Client
+from duniterpy.documents import Transaction
 
 logger = logging.getLogger("duniter/tx")
 
-URL_PATH = 'tx'
+MODULE = 'tx'
 
 HISTORY_SCHEMA = {
     "type": "object",
@@ -160,109 +161,100 @@ HISTORY_SCHEMA = {
 }
 
 SOURCES_SCHEMA = {
-        "type": "object",
-        "properties": {
-            "currency": {
-                "type": "string"
-            },
-            "pubkey": {
-                "type": "string"
-            },
-            "sources": {
-                "type": "array",
-                "items": {
-                    "type": "object",
-                    "properties": {
-                        "type": {
-                            "type": "string"
-                        },
-                        "noffset": {
-                            "type": "number"
-                        },
-                        "identifier": {
-                            "type": "string"
-                        },
-                        "amount": {
-                            "type": "number"
-                        },
-                        "base": {
-                            "type": "number"
-                        }
+    "type": "object",
+    "properties": {
+        "currency": {
+            "type": "string"
+        },
+        "pubkey": {
+            "type": "string"
+        },
+        "sources": {
+            "type": "array",
+            "items": {
+                "type": "object",
+                "properties": {
+                    "type": {
+                        "type": "string"
+                    },
+                    "noffset": {
+                        "type": "number"
+                    },
+                    "identifier": {
+                        "type": "string"
                     },
-                    "required": ["type", "noffset", "identifier", "amount", "base"]
-                }
+                    "amount": {
+                        "type": "number"
+                    },
+                    "base": {
+                        "type": "number"
+                    }
+                },
+                "required": ["type", "noffset", "identifier", "amount", "base"]
             }
-        },
-        "required": ["currency", "pubkey", "sources"]
-    }
+        }
+    },
+    "required": ["currency", "pubkey", "sources"]
+}
+
 
-async def history(connection, pubkey):
+async def history(client: Client, pubkey: str) -> dict:
     """
     Get transactions history of public key
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :param str pubkey: Public key
+    :param client: Client to connect to the api
+    :param pubkey: Public key
     :rtype: dict
     """
+    return await client.get(MODULE + '/history/%s' % pubkey, schema=HISTORY_SCHEMA)
 
-    client = API(connection, URL_PATH)
-
-    r = await client.requests_get( '/history/%s' % pubkey)
-    return await parse_response(r, HISTORY_SCHEMA)
-
-async def process(connection, transaction):
-    """
-    POST a transaction
-
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :param duniterpy.documents.Transaction transaction: Transaction document
-    :rtype: aiohttp.ClientResponse
-    """
-    client = API(connection, URL_PATH)
 
-    r = await client.requests_post('/process', transaction=transaction)
-    return r
+# async def process(client: Client, transaction: Transaction):
+#     """
+#     POST a transaction
+#
+#     :param client: Client to connect to the api
+#     :param transaction: Transaction document
+#     :rtype: aiohttp.ClientResponse
+#     """
+#     client = API(connection, MODULE)
+#
+#     r = await client.requests_post('/process', transaction=transaction)
+#     return r
 
 
-async def sources(connection, pubkey):
+async def sources(client: Client, pubkey: str):
     """
     GET transaction sources
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :param str pubkey: Public key
+    :param client: Client to connect to the api
+    :param pubkey: Public key
     :rtype: dict
     """
-    client = API(connection, URL_PATH)
+    return await client.get(MODULE + '/sources/%s' % pubkey, schema=SOURCES_SCHEMA)
 
-    r = await client.requests_get( '/sources/%s' % pubkey)
-    return await parse_response(r, SOURCES_SCHEMA)
 
-async def blocks(connection, pubkey, start, end):
+async def blocks(client: Client, pubkey: str, start: int, end: int) -> dict:
     """
     GET public key transactions history between start and end block number
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :param str pubkey: Public key
-    :param int start: Start from block number
-    :param int end: End to block number
+    :param client: Client to connect to the api
+    :param pubkey: Public key
+    :param start: Start from block number
+    :param end: End to block number
     :return: dict
     """
-    client = API(connection, URL_PATH)
+    return await client.get(MODULE + '/history/%s/blocks/%s/%s' % (pubkey, start, end), schema=HISTORY_SCHEMA)
 
-    r = await client.requests_get('/history/%s/blocks/%s/%s' % (pubkey, start, end))
-    return await parse_response(r, HISTORY_SCHEMA)
 
-async def times(connection, pubkey, start, end):
+async def times(client: Client, pubkey: str, start: int, end: int) -> dict:
     """
     GET public key transactions history between start and end timestamp
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :param str pubkey: Public key
-    :param int start: Start from timestamp
-    :param int end: End to timestamp
+    :param client: Client to connect to the api
+    :param pubkey: Public key
+    :param start: Start from timestamp
+    :param end: End to timestamp
     :return: dict
     """
-    client = API(connection, URL_PATH)
-
-    r = await client.requests_get('/history/%s/times/%s/%s' % (pubkey, start, end))
-    return await parse_response(r, HISTORY_SCHEMA)
+    return await client.get(MODULE + '/history/%s/times/%s/%s' % (pubkey, start, end), schema=HISTORY_SCHEMA)
diff --git a/duniterpy/api/bma/ud.py b/duniterpy/api/bma/ud.py
index 33e94a50e7b7a0d4dd44f58a1bcba293fb858cf8..1a97ea35b26c5634e246b4a695a49b265e0fc9de 100644
--- a/duniterpy/api/bma/ud.py
+++ b/duniterpy/api/bma/ud.py
@@ -14,13 +14,13 @@
 #
 # Authors:
 # Caner Candan <caner@candan.fr>, http://caner.candan.fr
-#
-
-from duniterpy.api.bma import logging, API, parse_response
+# vit
+import logging
+from duniterpy.api.client import Client
 
 logger = logging.getLogger("duniter/ud")
 
-URL_PATH = 'ud'
+MODULE = 'ud'
 
 UD_SCHEMA = {
     "type": "object",
@@ -64,16 +64,14 @@ UD_SCHEMA = {
     "required": ["currency", "pubkey", "history"]
 }
 
-async def history(connection, pubkey):
+
+async def history(client: Client, pubkey: str) -> dict:
     """
     Get UD history of a member account
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :param str pubkey:  Public key of the member
-
+    :param client: Client to connect to the api
+    :param pubkey:  Public key of the member
     :rtype: dict
     """
-    client = API(connection, URL_PATH)
+    return await client.get(MODULE + '/history/%s' % pubkey, schema=UD_SCHEMA)
 
-    r = await client.requests_get('/history/%s' % pubkey)
-    return await parse_response(r, UD_SCHEMA)
diff --git a/duniterpy/api/bma/wot.py b/duniterpy/api/bma/wot.py
index 45d5c86ac9ac07634bcdd2d72b7e152f67e4d20e..4b655d54761ac8cfb17c4b014cafa77b61a1bb80 100644
--- a/duniterpy/api/bma/wot.py
+++ b/duniterpy/api/bma/wot.py
@@ -14,13 +14,13 @@
 #
 # Authors:
 # Caner Candan <caner@candan.fr>, http://caner.candan.fr
-#
-from duniterpy.api.bma import API, logging, parse_response
+# vit
+import logging
+from duniterpy.api.client import Client
 
 logger = logging.getLogger("duniter/wot")
 
-URL_PATH = 'wot'
-
+MODULE = 'wot'
 
 CERTIFICATIONS_SCHEMA = {
     "type": "object",
@@ -297,109 +297,98 @@ LOOKUP_SCHEMA = {
     "required": ["partial", "results"]
 }
 
-async def add(connection, identity):
-    """
-    POST identity document
-
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :param duniterpy.documents.certification.Identity identity: Identity document
-    :rtype: aiohttp.ClientResponse
-    """
-    client = API(connection, URL_PATH)
-
-    r = await client.requests_post('/add', identity=identity)
-    return r
 
-async def certify(connection, cert):
-    """
-    POST certification document
-
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :param duniterpy.documents.certification.Certification cert: Certification document
-    :rtype: aiohttp.ClientResponse
-    """
-    client = API(connection, URL_PATH)
+# async def add(client: Client, identity: str) -> dict:
+#     """
+#     POST identity document
+#
+#     :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
+#     :param duniterpy.documents.certification.Identity identity: Identity document
+#     :rtype: aiohttp.ClientResponse
+#     """
+#     client = API(connection, URL_PATH)
+#
+#     r = await client.requests_post('/add', identity=identity)
+#     return r
 
-    r = await client.requests_post('/certify', cert=cert)
-    return r
 
-async def revoke(connection, revocation):
-    """
-    POST revocation document
+# async def certify(connection, cert):
+#     """
+#     POST certification document
+#
+#     :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
+#     :param duniterpy.documents.certification.Certification cert: Certification document
+#     :rtype: aiohttp.ClientResponse
+#     """
+#     client = API(connection, URL_PATH)
+#
+#     r = await client.requests_post('/certify', cert=cert)
+#     return r
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :param duniterpy.documents.certification.Revocation revocation: Certification document
-    :rtype: aiohttp.ClientResponse
-    """
-    client = API(connection, URL_PATH)
 
-    r = await client.requests_post('/revoke', revocation=revocation)
-    return r
+# async def revoke(connection, revocation):
+#     """
+#     POST revocation document
+#
+#     :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
+#     :param duniterpy.documents.certification.Revocation revocation: Certification document
+#     :rtype: aiohttp.ClientResponse
+#     """
+#     client = API(connection, URL_PATH)
+#
+#     r = await client.requests_post('/revoke', revocation=revocation)
+#     return r
 
 
-async def lookup(connection, search):
+async def lookup(client: Client, search: str) -> dict:
     """
     GET UID/Public key data
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :param str search: UID or public key
+    :param client: Client to connect to the api
+    :param search: UID or public key
     :rtype: dict
     """
-    client = API(connection, URL_PATH)
-
-    r = await client.requests_get('/lookup/%s' % search)
-    return await parse_response(r, LOOKUP_SCHEMA)
+    return await client.get(MODULE + '/lookup/%s' % search, schema=LOOKUP_SCHEMA)
 
 
-async def certifiers_of(connection, search):
+async def certifiers_of(client: Client, search: str) -> dict:
     """
     GET UID/Public key certifiers
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :param str search: UID or public key
+    :param client: Client to connect to the api
+    :param search: UID or public key
     :rtype: dict
     """
+    return await client.get(MODULE + '/certifiers-of/%s' % search, schema=CERTIFICATIONS_SCHEMA)
 
-    client = API(connection, URL_PATH)
-
-    r = await client.requests_get('/certifiers-of/%s' % search)
-    return await parse_response(r, CERTIFICATIONS_SCHEMA)
 
-async def certified_by(connection, search):
+async def certified_by(client: Client, search: str) -> dict:
     """
     GET identities certified by UID/Public key
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :param str search: UID or public key
+    :param client: Client to connect to the api
+    :param search: UID or public key
     :rtype: dict
     """
-    client = API(connection, URL_PATH)
+    return await client.get(MODULE + '/certified-by/%s' % search, schema=CERTIFICATIONS_SCHEMA)
 
-    r = await client.requests_get('/certified-by/%s' % search)
-    return await parse_response(r, CERTIFICATIONS_SCHEMA)
 
-async def members(connection):
+async def members(client: Client) -> dict:
     """
     GET list of all current members of the Web of Trust
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
+    :param client: Client to connect to the api
     :rtype: dict
     """
-    client = API(connection, URL_PATH)
+    return await client.get(MODULE + '/members', schema=MEMBERS_SCHEMA)
 
-    r = await client.requests_get('/members')
-    return await parse_response(r, MEMBERS_SCHEMA)
 
-
-async def requirements(connection, search):
+async def requirements(client: Client, search: str) -> dict:
     """
     GET list of requirements for a given UID/Public key
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :param str search: UID or public key
+    :param client: Client to connect to the api
+    :param search: UID or public key
     :rtype: dict
     """
-    client = API(connection, URL_PATH)
-
-    r = await client.requests_get('/requirements/%s' % search)
-    return await parse_response(r, REQUIREMENTS_SCHEMA)
+    return await client.get(MODULE + '/requirements/%s' % search, schema=REQUIREMENTS_SCHEMA)
diff --git a/duniterpy/api/bma/ws.py b/duniterpy/api/bma/ws.py
index 6e36fddd19e5af4cce81c04962a400253c20c55e..ecd857f08070e48a642e2685d85ecbd8803d84a0 100644
--- a/duniterpy/api/bma/ws.py
+++ b/duniterpy/api/bma/ws.py
@@ -15,16 +15,17 @@
 # Authors:
 # Caner Candan <caner@candan.fr>, http://caner.candan.fr
 #
-
-from duniterpy.api.bma import API, logging
+# vit
+import logging
+from duniterpy.api.client import Client
 from duniterpy.api.bma.blockchain import BLOCK_SCHEMA
 
 logger = logging.getLogger("duniter/ws")
 
-URL_PATH = 'ws'
+MODULE = 'ws'
 
+WS_BLOCK_SCHEMA = BLOCK_SCHEMA
 
-WS_BLOCk_SCHEMA = BLOCK_SCHEMA
 WS_PEER_SCHEMA = {
     "type": "object",
     "properties": {
@@ -51,23 +52,23 @@ WS_PEER_SCHEMA = {
 }
 
 
-def block(connection):
-    """
-    Connect to block websocket
-
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :rtype: aiohttp.ClientWebSocketResponse
-    """
-    client = API(connection, URL_PATH)
-    return client.connect_ws('/block')
-
+# def block(client: Client):
+#     """
+#     Connect to block websocket
+#
+#     :param client: Client to connect to the api
+#     :rtype: aiohttp.ClientWebSocketResponse
+#     """
+#     client = API(connection, MODULE)
+#     return client.connect_ws('/block')
 
-def peer(connection):
-    """
-    Connect to peer websocket
 
-    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
-    :rtype: aiohttp.ClientWebSocketResponse
-    """
-    client = API(connection, URL_PATH)
-    return client.connect_ws('/peer')
+# def peer(client: Client):
+#     """
+#     Connect to peer websocket
+#
+#     :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
+#     :rtype: aiohttp.ClientWebSocketResponse
+#     """
+#     client = API(connection, MODULE)
+#     return client.connect_ws('/peer')
diff --git a/duniterpy/api/bma/api.py b/duniterpy/api/client.py
similarity index 71%
rename from duniterpy/api/bma/api.py
rename to duniterpy/api/client.py
index 29fd926d43fb4b29d4ee2d1b6a692c502b5e50f8..1599fbfeb0c23393615c52fb7ece21d62694e567 100644
--- a/duniterpy/api/bma/api.py
+++ b/duniterpy/api/client.py
@@ -1,28 +1,13 @@
-#
-#
-# This program is free software: you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation, either version 3 of the License, or
-# (at your option) any later version.
-#
-# This program is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program.  If not, see <http://www.gnu.org/licenses/>.
-#
 # Authors:
 # Caner Candan <caner@candan.fr>, http://caner.candan.fr
 # Inso <insomniak.fr at gmail.com>
 
-
-import aiohttp
 import json
 import logging
+import aiohttp
 import jsonschema
-from ..errors import DuniterError
+from .errors import DuniterError
+from duniterpy.api.endpoint import endpoint
 
 logger = logging.getLogger("duniter")
 
@@ -40,34 +25,12 @@ ERROR_SCHEMA = {
 }
 
 
-class ConnectionHandler(object):
-    """Helper class used by other API classes to ease passing server connection information."""
-
-    def __init__(self, http_scheme, ws_scheme, server, port, path="", proxy=None, session=None):
-        """
-        Init instance of connection handler
-
-        :param str server: Server IP or domaine name
-        :param int port: Port
-        :param aiohttp.ClientSession|None session: Session AIOHTTP
-        """
-        self.http_scheme = http_scheme
-        self.ws_scheme = ws_scheme
-        self.server = server
-        self.proxy = proxy
-        self.port = port
-        self.session = session
-        self.path = path
-
-    def __str__(self):
-        return 'connection info: %s:%d' % (self.server, self.port)
-
-
 def parse_text(text, schema):
     """
     Validate and parse the BMA answer from websocket
 
     :param str text: the bma answer
+    :param dict schema: dict for jsonschema
     :return: the json data
     """
     try:
@@ -112,7 +75,8 @@ async def parse_response(response, schema):
 
 
 class API(object):
-    """APIRequest is a class used as an interface. The intermediate derivated classes are the modules and the leaf classes are the API requests."""
+    """APIRequest is a class used as an interface. The intermediate derivated classes are the modules and the leaf
+    classes are the API requests. """
 
     schema = {}
 
@@ -139,15 +103,15 @@ class API(object):
         server, port = self.connection_handler.server, self.connection_handler.port
         if self.connection_handler.path:
             url = '{scheme}://{server}:{port}/{path}/{module}'.format(scheme=scheme,
-                                                                  server=server,
-                                                                  port=port,
-                                                                  path=path,
-                                                                  module=self.module)
+                                                                      server=server,
+                                                                      port=port,
+                                                                      path=path,
+                                                                      module=self.module)
         else:
             url = '{scheme}://{server}:{port}/{module}'.format(scheme=scheme,
-                                                                  server=server,
-                                                                  port=port,
-                                                                  module=self.module)
+                                                               server=server,
+                                                               port=port,
+                                                               module=self.module)
 
         return url + path
 
@@ -201,3 +165,57 @@ class API(object):
         """
         url = self.reverse_url(self.connection_handler.ws_scheme, path)
         return self.connection_handler.session.ws_connect(url, proxy=self.connection_handler.proxy)
+
+
+class Client:
+    """
+    Main class to create an API client
+    """
+    def __init__(self, _endpoint: str, session: aiohttp.ClientSession = None, proxy: str = None):
+        """
+        Init Client instance
+
+        :param _endpoint: Endpoint string in duniter format
+        :param session: Aiohttp client session (optional, default None)
+        :param proxy: Proxy server as hostname:port
+        """
+        # Endpoint Protocol detection
+        self.endpoint = endpoint(_endpoint)
+
+        # if no user session...
+        if session is None:
+            # open a session
+            self.session = aiohttp.ClientSession()
+        else:
+            self.session = session
+        self.proxy = proxy
+
+    async def get(self, url_path: str, params: dict = None, schema: dict = None)-> any:
+        """
+        Get request on self.endpoint + url_path
+
+        :param url_path: Url encoded path following the endpoint
+        :param params: Url query string parameters dictionary
+        :param schema: Json Schema to validate response (optional, default None)
+        :return:
+        """
+        if params is None:
+            params = dict()
+
+        client = API(self.endpoint.conn_handler(self.session, self.proxy), '')
+
+        response = await client.requests_get(url_path, **params)
+
+        if schema is not None:
+            return await parse_response(response, schema)
+        else:
+            return await response.json()
+
+    async def close(self):
+        """
+        Close aiohttp session
+
+        :return:
+        """
+        await self.session.close()
+
diff --git a/duniterpy/api/constants.py b/duniterpy/api/constants.py
new file mode 100644
index 0000000000000000000000000000000000000000..4ca0a4d93be336a1f7451b9addc84e07a2c311d4
--- /dev/null
+++ b/duniterpy/api/constants.py
@@ -0,0 +1,20 @@
+
+uid_regex = "[A-Za-z0-9_-]{2,100}"
+pubkey_regex = "(?![OIl])[1-9A-Za-z]{42,45}"
+signature_regex = "[A-Za-z0-9+/]+(?:=|==)?"
+block_hash_regex = "[0-9a-fA-F]{5,64}"
+transaction_hash_regex = "[0-9a-fA-F]{5,64}"
+hash_regex = "[A-F0-9]{64}"
+block_id_regex = "[0-9]+"
+block_uid_regex = "{block_id_regex}-{block_hash_regex}".format(block_id_regex=block_id_regex,
+                                                              block_hash_regex=block_hash_regex)
+conditions_regex = "(&&|\|\|| |[()]|(SIG\({pubkey_regex}\)|(XHX\({hash_regex}\))))*"\
+    .format(pubkey_regex=pubkey_regex, hash_regex=hash_regex)
+ipv4_regex = '(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])'
+ipv6_regex = '(?:(?:[0-9A-Fa-f]{1,4}:){6}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|::(?:[0-9A-Fa-f]{1,4}:){5}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){4}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){3}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,2}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:){2}(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,3}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}:(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,4}[0-9A-Fa-f]{1,4})?::(?:[0-9A-Fa-f]{1,4}:[0-9A-Fa-f]{1,4}|(?:(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\\.){3}(?:[0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5]))|(?:(?:[0-9A-Fa-f]{1,4}:){,5}[0-9A-Fa-f]{1,4})?::[0-9A-Fa-f]{1,4}|(?:(?:[0-9A-Fa-f]{1,4}:){,6}[0-9A-Fa-f]{1,4})?::)(?:%.+)?'
+ws2pid_regex = "[0-9a-f]{8}"
+host_regex = "[a-z0-9-_.]*(?:.[a-zA-Z])?"
+path_regex = "[/\w \.-]*/?"
+ws2p_private_prefix_regex = "O[CT][SAM]"
+ws2p_public_prefix_regex = "I[CT]"
+ws2p_head_regex = "HEAD:?(?:[0-9]+)?"
diff --git a/duniterpy/api/elasticsearch/__init__.py b/duniterpy/api/elasticsearch/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/duniterpy/api/endpoint.py b/duniterpy/api/endpoint.py
new file mode 100644
index 0000000000000000000000000000000000000000..e4c4f7963328cb891494077b3c54e8716e30522e
--- /dev/null
+++ b/duniterpy/api/endpoint.py
@@ -0,0 +1,427 @@
+import re
+import aiohttp
+from .constants import *
+from ..documents import MalformedDocumentError
+
+
+class ConnectionHandler:
+    """Helper class used by other API classes to ease passing server connection information."""
+
+    def __init__(self, http_scheme: str, ws_scheme: str, server: str, port: int, path: str = "", proxy: str = None, session: aiohttp.ClientSession = None):
+        """
+        Init instance of connection handler
+
+        :param http_scheme: Http scheme
+        :param ws_scheme: Web socket scheme
+        :param server: Server IP or domain name
+        :param port: Port number
+        :param port: Url path (optional, default="")
+        :param proxy: Proxy (optional, default=None)
+        :param session: Session AIOHTTP (optional, default=None)
+        """
+        self.http_scheme = http_scheme
+        self.ws_scheme = ws_scheme
+        self.server = server
+        self.port = port
+        self.path = path
+        self.proxy = proxy
+        self.session = session
+
+    def __str__(self)-> str:
+        return 'connection info: %s:%d' % (self.server, self.port)
+
+
+class Endpoint:
+    @classmethod
+    def from_inline(cls, inline: str):
+        raise NotImplementedError("from_inline(..) is not implemented")
+
+    def inline(self) -> str:
+        raise NotImplementedError("inline() is not implemented")
+
+    def __str__(self) -> str:
+        raise NotImplementedError("__str__ is not implemented")
+
+    def __eq__(self, other: any) -> bool:
+        raise NotImplementedError("__eq__ is not implemented")
+
+
+class UnknownEndpoint(Endpoint):
+    API = None
+
+    def __init__(self, api: str, properties: list):
+        self.api = api
+        self.properties = properties
+
+    @classmethod
+    def from_inline(cls, inline: str):
+        """
+        Return UnknownEndpoint instance from endpoint string
+
+        :param inline: Endpoint string
+        :return:
+        """
+        try:
+            api = inline.split()[0]
+            properties = inline.split()[1:]
+            return cls(api, properties)
+        except IndexError:
+            raise MalformedDocumentError(inline)
+
+    def inline(self) -> str:
+        """
+        Return endpoint string
+
+        :return:
+        """
+        doc = self.api
+        for p in self.properties:
+            doc += " {0}".format(p)
+        return doc
+
+    def __str__(self) -> str:
+        return "{0} {1}".format(self.api, ' '.join(["{0}".format(p) for p in self.properties]))
+
+    def __eq__(self, other: any) -> bool:
+        if isinstance(other, UnknownEndpoint):
+            return self.api == other.api and self.properties == other.properties
+        else:
+            return False
+
+    def __hash__(self) -> int:
+        return hash((self.api, self.properties))
+
+
+ERROR_SCHEMA = {
+    "type": "object",
+    "properties": {
+        "ucode": {
+            "type": "number"
+        },
+        "message": {
+            "type": "string"
+        }
+    },
+    "required": ["ucode", "message"]
+}
+
+
+class BMAEndpoint(Endpoint):
+    API = "BASIC_MERKLED_API"
+    re_inline = re.compile(
+        '^BASIC_MERKLED_API(?: ({host_regex}))?(?: ({ipv4_regex}))?(?: ({ipv6_regex}))?(?: ([0-9]+))$'.format(
+            host_regex=host_regex,
+            ipv4_regex=ipv4_regex,
+            ipv6_regex=ipv6_regex))
+
+    def __init__(self, server: str, ipv4: str, ipv6: str, port: int):
+        """
+        Init BMAEndpoint instance
+
+        :param server: IP or domain name
+        :param ipv4: IP as IPv4 format
+        :param ipv6: IP as IPv6 format
+        :param port: Port number
+        """
+        self.server = server
+        self.ipv4 = ipv4
+        self.ipv6 = ipv6
+        self.port = port
+
+    @classmethod
+    def from_inline(cls, inline: str):
+        """
+        Return BMAEndpoint instance from endpoint string
+
+        :param inline:
+        :return:
+        """
+        m = BMAEndpoint.re_inline.match(inline)
+        if m is None:
+            raise MalformedDocumentError(BMAEndpoint.API)
+        server = m.group(1)
+        ipv4 = m.group(2)
+        ipv6 = m.group(3)
+        port = int(m.group(4))
+        return cls(server, ipv4, ipv6, port)
+
+    def inline(self) -> str:
+        """
+        Return endpoint string
+
+        :return:
+        """
+        return BMAEndpoint.API + "{DNS}{IPv4}{IPv6}{PORT}" \
+                    .format(DNS=(" {0}".format(self.server) if self.server else ""),
+                            IPv4=(" {0}".format(self.ipv4) if self.ipv4 else ""),
+                            IPv6=(" {0}".format(self.ipv6) if self.ipv6 else ""),
+                            PORT=(" {0}".format(self.port) if self.port else ""))
+
+    # fixme: session must be mandatory
+    def conn_handler(self, session: aiohttp.ClientSession = None, proxy: str = None) -> ConnectionHandler:
+        """
+        Return connection handler instance for the endpoint
+
+        :param session: AIOHTTP client session instance
+        :param proxy: Proxy url
+        :return:
+        """
+        if self.server:
+            return ConnectionHandler("http", "ws", self.server, self.port, "", proxy, session)
+        elif self.ipv6:
+            return ConnectionHandler("http", "ws", "[{0}]".format(self.ipv6), self.port, "", proxy, session)
+
+        return ConnectionHandler("http", "ws", self.ipv4, self.port, "", proxy, session)
+
+    def __str__(self):
+        return self.inline()
+
+    def __eq__(self, other):
+        if isinstance(other, BMAEndpoint):
+            return self.server == other.server and self.ipv4 == other.ipv4 \
+                    and self.ipv6 == other.ipv6 and self.port == other.port
+        else:
+            return False
+
+    def __hash__(self):
+        return hash((self.server, self.ipv4, self.ipv6, self.port))
+
+
+class SecuredBMAEndpoint(BMAEndpoint):
+    API = "BMAS"
+    re_inline = re.compile(
+        '^BMAS(?: ({host_regex}))?(?: ({ipv4_regex}))?(?: ({ipv6_regex}))? ([0-9]+)(?: ({path_regex}))?$'.format(
+            host_regex=host_regex,
+            ipv4_regex=ipv4_regex,
+            ipv6_regex=ipv6_regex,
+            path_regex=path_regex))
+
+    def __init__(self, server: str, ipv4: str, ipv6: str, port: int, path: str):
+        """
+        Init SecuredBMAEndpoint instance
+
+        :param server: IP or domain name
+        :param ipv4: IP as IPv4 format
+        :param ipv6: IP as IPv6 format
+        :param port: Port number
+        :param path: Url path
+        """
+        super().__init__(server, ipv4, ipv6, port)
+        self.path = path
+
+    @classmethod
+    def from_inline(cls, inline: str):
+        """
+        Return SecuredBMAEndpoint instance from endpoint string
+
+        :param inline:
+        :return:
+        """
+        m = SecuredBMAEndpoint.re_inline.match(inline)
+        if m is None:
+            raise MalformedDocumentError(SecuredBMAEndpoint.API)
+        server = m.group(1)
+        ipv4 = m.group(2)
+        ipv6 = m.group(3)
+        port = int(m.group(4))
+        path = m.group(5)
+        if not path:
+            path = ""
+        return cls(server, ipv4, ipv6, port, path)
+
+    def inline(self) -> str:
+        """
+        Return endpoint string
+
+        :return:
+        """
+        inlined = [str(info) for info in (self.server, self.ipv4, self.ipv6, self.port, self.path) if info]
+        return SecuredBMAEndpoint.API + " " + " ".join(inlined)
+
+    # fixme: session must be mandatory
+    def conn_handler(self, session: aiohttp.ClientSession = None, proxy: str = None) -> ConnectionHandler:
+        """
+        Return connection handler instance for the endpoint
+
+        :param session: AIOHTTP client session instance
+        :param proxy: Proxy url
+        :return:
+        """
+        if self.server:
+            return ConnectionHandler("https", "wss", self.server, self.port, self.path, proxy, session)
+        elif self.ipv6:
+            return ConnectionHandler("https", "wss", "[{0}]".format(self.ipv6), self.port, self.path, proxy, session)
+
+        return ConnectionHandler("https", "wss", self.ipv4, self.port, self.path, proxy, session)
+
+
+class WS2PEndpoint(Endpoint):
+    API = "WS2P"
+    re_inline = re.compile(
+        '^WS2P ({ws2pid_regex}) ((?:{host_regex})|(?:{ipv4_regex})) ([0-9]+)?(?: ({path_regex}))?$'.format(
+            ws2pid_regex=ws2pid_regex,
+            host_regex=host_regex,
+            ipv4_regex=ipv4_regex,
+            ipv6_regex=ipv6_regex,
+            path_regex=path_regex))
+
+    def __init__(self, ws2pid, server, port, path):
+        self.ws2pid = ws2pid
+        self.server = server
+        self.port = port
+        self.path = path
+
+    @classmethod
+    def from_inline(cls, inline):
+        m = WS2PEndpoint.re_inline.match(inline)
+        if m is None:
+            raise MalformedDocumentError(WS2PEndpoint.API)
+        ws2pid = m.group(1)
+        server = m.group(2)
+        port = int(m.group(3))
+        path = m.group(4)
+        if not path:
+            path = ""
+        return cls(ws2pid, server, port, path)
+
+    def inline(self):
+        inlined = [str(info) for info in (self.ws2pid, self.server, self.port, self.path) if info]
+        return WS2PEndpoint.API + " " + " ".join(inlined)
+
+    def conn_handler(self, session: aiohttp.ClientSession = None, proxy: str = None) -> ConnectionHandler:
+        """
+        Return connection handler instance for the endpoint
+
+        :param aiohttp.ClientSession session: AIOHTTP client session instance
+        :param str proxy: Proxy url
+        :rtype: ConnectionHandler
+        """
+        return ConnectionHandler("https", "wss", self.server, self.port, self.path, proxy, session)
+
+    def __str__(self):
+        return self.inline()
+
+    def __eq__(self, other):
+        if isinstance(other, WS2PEndpoint):
+            return self.server == other.server and self.ws2pid == other.ws2pid \
+                    and self.port == other.port and self.path == other.path
+        else:
+            return False
+
+    def __hash__(self):
+        return hash((self.ws2pid, self.server, self.port, self.path))
+
+
+class ESUserEndpoint(Endpoint):
+    API = "ES_USER_API"
+    re_inline = re.compile(
+        '^ES_USER_API ((?:{host_regex})|(?:{ipv4_regex})) ([0-9]+)$'.format(ws2pid_regex=ws2pid_regex,
+                                                                            host_regex=host_regex,
+                                                                            ipv4_regex=ipv4_regex))
+
+    def __init__(self, server, port):
+        self.server = server
+        self.port = port
+
+    @classmethod
+    def from_inline(cls, inline):
+        m = ESUserEndpoint.re_inline.match(inline)
+        if m is None:
+            raise MalformedDocumentError(ESUserEndpoint.API)
+        server = m.group(1)
+        port = int(m.group(2))
+        return cls(server, port)
+
+    def inline(self):
+        inlined = [str(info) for info in (self.server, self.port) if info]
+        return ESUserEndpoint.API + " " + " ".join(inlined)
+
+    def conn_handler(self, session: aiohttp.ClientSession = None, proxy: str = None) -> ConnectionHandler:
+        """
+        Return connection handler instance for the endpoint
+
+        :param aiohttp.ClientSession session: AIOHTTP client session instance
+        :param str proxy: Proxy url
+        :rtype: ConnectionHandler
+        """
+        return ConnectionHandler("https", "wss", self.server, self.port, "", proxy, session)
+
+    def __str__(self):
+        return self.inline()
+
+    def __eq__(self, other):
+        if isinstance(other, ESUserEndpoint):
+            return self.server == other.server and self.port == other.port
+        else:
+            return False
+
+    def __hash__(self):
+        return hash((self.server, self.port))
+
+
+class ESSubscribtionEndpoint(Endpoint):
+    API = "ES_SUBSCRIPTION_API"
+    re_inline = re.compile(
+        '^ES_SUBSCRIPTION_API ((?:{host_regex})|(?:{ipv4_regex})) ([0-9]+)$'.format(ws2pid_regex=ws2pid_regex,
+                                                                                    host_regex=host_regex,
+                                                                                    ipv4_regex=ipv4_regex))
+
+    def __init__(self, server, port):
+        self.server = server
+        self.port = port
+
+    @classmethod
+    def from_inline(cls, inline):
+        m = ESSubscribtionEndpoint.re_inline.match(inline)
+        if m is None:
+            raise MalformedDocumentError(ESSubscribtionEndpoint.API)
+        server = m.group(1)
+        port = int(m.group(2))
+        return cls(server, port)
+
+    def inline(self):
+        inlined = [str(info) for info in (self.server, self.port) if info]
+        return ESSubscribtionEndpoint.API + " " + " ".join(inlined)
+
+    def conn_handler(self, session: aiohttp.ClientSession = None, proxy: str = None) -> ConnectionHandler:
+        """
+        Return connection handler instance for the endpoint
+
+        :param aiohttp.ClientSession session: AIOHTTP client session instance
+        :param str proxy: Proxy url
+        :rtype: ConnectionHandler
+        """
+        return ConnectionHandler("https", "wss", self.server, self.port, "", proxy, session)
+
+    def __str__(self):
+        return self.inline()
+
+    def __eq__(self, other):
+        if isinstance(other, ESSubscribtionEndpoint):
+            return self.server == other.server and self.port == other.port
+        else:
+            return False
+
+    def __hash__(self):
+        return hash((ESSubscribtionEndpoint.API, self.server, self.port))
+
+
+MANAGED_API = {
+    BMAEndpoint.API: BMAEndpoint,
+    SecuredBMAEndpoint.API: SecuredBMAEndpoint,
+    WS2PEndpoint.API: WS2PEndpoint,
+    ESUserEndpoint.API: ESUserEndpoint,
+    ESSubscribtionEndpoint.API: ESSubscribtionEndpoint
+}
+
+
+def endpoint(value):
+    if issubclass(type(value), Endpoint):
+        return value
+    elif isinstance(value, str):
+        for api, cls in MANAGED_API.items():
+            if value.startswith(api + " "):
+                return cls.from_inline(value)
+        return UnknownEndpoint.from_inline(value)
+    else:
+        raise TypeError("Cannot convert {0} to endpoint".format(value))
diff --git a/duniterpy/api/ws2p/__init__.py b/duniterpy/api/ws2p/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/duniterpy/api/ws2p/network.py b/duniterpy/api/ws2p/network.py
new file mode 100644
index 0000000000000000000000000000000000000000..14b331c53ced6cd584bd7f873f7502ad6c9c89d1
--- /dev/null
+++ b/duniterpy/api/ws2p/network.py
@@ -0,0 +1,68 @@
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+#
+# Authors:
+# Caner Candan <caner@candan.fr>, http://caner.candan.fr
+#
+
+from duniterpy.api.client import API, logging, parse_response
+
+logger = logging.getLogger("duniter/network")
+
+URL_PATH = '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"]
+                            }
+                        }
+                    },
+                    "required": ["heads"]
+                }
+
+
+async def heads(connection):
+    """
+    GET Certification data over a member
+
+    :param duniterpy.api.bma.ConnectionHandler connection: Connection handler instance
+    :rtype: dict
+    """
+
+    client = API(connection, URL_PATH)
+
+    r = await client.requests_get('/ws2p/heads')
+    return await parse_response(r, WS2P_HEADS_SCHEMA)
diff --git a/duniterpy/documents/__init__.py b/duniterpy/documents/__init__.py
index e313598de4c22196820c19d6e82f7dcc0a120338..29f7818a822fd811521c7ec63ccb9e041d42858c 100644
--- a/duniterpy/documents/__init__.py
+++ b/duniterpy/documents/__init__.py
@@ -1,7 +1,6 @@
 from .block import Block, BlockUID, block_uid
 from .certification import Identity, Certification, Revocation
 from .membership import Membership
-from .peer import endpoint, BMAEndpoint, UnknownEndpoint, Peer, SecuredBMAEndpoint, WS2PEndpoint
 from .transaction import SimpleTransaction, Transaction, InputSource, OutputSource, \
     SIGParameter, Unlock, UnlockParameter
 from .document import Document, MalformedDocumentError
diff --git a/duniterpy/documents/peer.py b/duniterpy/documents/peer.py
index a638d53655f6fd6df78a0697fcafff3c9f8e4dbf..60255e123109de1c9862d999896be8c3d6fea017 100644
--- a/duniterpy/documents/peer.py
+++ b/duniterpy/documents/peer.py
@@ -1,11 +1,9 @@
 import re
-import aiohttp
-from typing import Generator
 
-from ..api.bma import ConnectionHandler
-from .document import Document, MalformedDocumentError
+from duniterpy.api.endpoint import endpoint
+from .document import Document
 from . import BlockUID
-from .constants import block_hash_regex, pubkey_regex, ipv4_regex, ipv6_regex, ws2pid_regex, host_regex, path_regex
+from .constants import block_hash_regex, pubkey_regex
 
 
 class Peer(Document):
@@ -37,12 +35,12 @@ class Peer(Document):
         "Endpoints": re_endpoints
     }}
 
-    def __init__(self, version, currency, pubkey, blockUID,
+    def __init__(self, version, currency, pubkey, block_uid,
                  endpoints, signature):
         super().__init__(version, currency, [signature])
 
         self.pubkey = pubkey
-        self.blockUID = blockUID
+        self.blockUID = block_uid
         self.endpoints = endpoints
 
     @classmethod
@@ -62,7 +60,7 @@ class Peer(Document):
         pubkey = Peer.parse_field("Pubkey", lines[n])
         n += 1
 
-        blockUID = BlockUID.from_str(Peer.parse_field("Block", lines[n]))
+        block_uid = BlockUID.from_str(Peer.parse_field("Block", lines[n]))
         n += 1
 
         Peer.parse_field("Endpoints", lines[n])
@@ -75,7 +73,7 @@ class Peer(Document):
 
         signature = Peer.re_signature.match(lines[n]).group(1)
 
-        return cls(version, currency, pubkey, blockUID, endpoints, signature)
+        return cls(version, currency, pubkey, block_uid, endpoints, signature)
 
     def raw(self):
         doc = """Version: {0}
@@ -86,330 +84,7 @@ Block: {3}
 Endpoints:
 """.format(self.version, self.currency, self.pubkey, self.blockUID)
 
-        for endpoint in self.endpoints:
-            doc += "{0}\n".format(endpoint.inline())
+        for _endpoint in self.endpoints:
+            doc += "{0}\n".format(_endpoint.inline())
 
         return doc
-
-
-def endpoint(value):
-    if issubclass(type(value), Endpoint):
-        return value
-    elif isinstance(value, str):
-        for api, cls in MANAGED_API.items():
-            if value.startswith(api + " "):
-                return cls.from_inline(value)
-        return UnknownEndpoint.from_inline(value)
-    else:
-        raise TypeError("Cannot convert {0} to endpoint".format(value))
-
-
-class Endpoint():
-    @classmethod
-    def from_inline(cls, inline):
-        raise NotImplementedError("from_inline(..) is not implemented")
-
-    def inline(self):
-        raise NotImplementedError("inline() is not implemented")
-
-    def __str__(self):
-        raise NotImplementedError("__str__ is not implemented")
-
-    def __eq__(self, other):
-        raise NotImplementedError("__eq__ is not implemented")
-
-
-class UnknownEndpoint(Endpoint):
-    API = None
-
-    def __init__(self, api, properties):
-        self.api = api
-        self.properties = properties
-
-    @classmethod
-    def from_inline(cls, inline):
-        try:
-            api = inline.split()[0]
-            properties = inline.split()[1:]
-            return cls(api, properties)
-        except IndexError:
-            raise MalformedDocumentError(inline)
-
-    def inline(self):
-        doc = self.api
-        for p in self.properties:
-            doc += " {0}".format(p)
-        return doc
-
-    def __str__(self):
-        return "{0} {1}".format(self.api, ' '.join(["{0}".format(p) for p in self.properties]))
-
-    def __eq__(self, other):
-        if isinstance(other, UnknownEndpoint):
-            return self.api == other.api and self.properties == other.properties
-        else:
-            return False
-
-    def __hash__(self):
-        return hash((self.api, self.properties))
-
-
-class BMAEndpoint(Endpoint):
-    API = "BASIC_MERKLED_API"
-    re_inline = re.compile('^BASIC_MERKLED_API(?: ({host_regex}))?(?: ({ipv4_regex}))?(?: ({ipv6_regex}))?(?: ([0-9]+))$'.format(host_regex=host_regex,
-                                                                                                                                 ipv4_regex=ipv4_regex,
-                                                                                                                                 ipv6_regex=ipv6_regex))
-
-    def __init__(self, server, ipv4, ipv6, port):
-        self.server = server
-        self.ipv4 = ipv4
-        self.ipv6 = ipv6
-        self.port = port
-
-    @classmethod
-    def from_inline(cls, inline):
-        m = BMAEndpoint.re_inline.match(inline)
-        str_re = BMAEndpoint.re_inline.pattern
-        if m is None:
-            raise MalformedDocumentError(BMAEndpoint.API)
-        server = m.group(1)
-        ipv4 = m.group(2)
-        ipv6 = m.group(3)
-        port = int(m.group(4))
-        return cls(server, ipv4, ipv6, port)
-
-    def inline(self):
-        return BMAEndpoint.API + "{DNS}{IPv4}{IPv6}{PORT}" \
-                    .format(DNS=(" {0}".format(self.server) if self.server else ""),
-                            IPv4=(" {0}".format(self.ipv4) if self.ipv4 else ""),
-                            IPv6=(" {0}".format(self.ipv6) if self.ipv6 else ""),
-                            PORT=(" {0}".format(self.port) if self.port else ""))
-
-    def conn_handler(self, session: aiohttp.ClientSession = None, proxy: str = None) -> ConnectionHandler:
-        """
-        Return connection handler instance for the endpoint
-
-        :param aiohttp.ClientSession session: AIOHTTP client session instance
-        :param str proxy: Proxy url
-        :rtype: ConnectionHandler
-        """
-        if self.server:
-            return ConnectionHandler("http", "ws", self.server, self.port, "", proxy, session)
-        elif self.ipv6:
-            return ConnectionHandler("http", "ws", "[{0}]".format(self.ipv6), self.port, "", proxy, session)
-
-        return ConnectionHandler("http", "ws", self.ipv4, self.port, "", proxy, session)
-
-    def __str__(self):
-        return self.inline()
-
-    def __eq__(self, other):
-        if isinstance(other, BMAEndpoint):
-            return self.server == other.server and self.ipv4 == other.ipv4 \
-                    and self.ipv6 == other.ipv6 and self.port == other.port
-        else:
-            return False
-
-    def __hash__(self):
-        return hash((self.server, self.ipv4, self.ipv6, self.port))
-
-
-class SecuredBMAEndpoint(BMAEndpoint):
-    API = "BMAS"
-    re_inline = re.compile('^BMAS(?: ({host_regex}))?(?: ({ipv4_regex}))?(?: ({ipv6_regex}))? ([0-9]+)(?: ({path_regex}))?$'.format(host_regex=host_regex,
-                                                                                                                                   ipv4_regex=ipv4_regex,
-                                                                                                                                   ipv6_regex=ipv6_regex,
-                                                                                                                                   path_regex=path_regex))
-
-    def __init__(self, server, ipv4, ipv6, port, path):
-        super().__init__(server, ipv4, ipv6, port)
-        self.path = path
-
-    @classmethod
-    def from_inline(cls, inline):
-        m = SecuredBMAEndpoint.re_inline.match(inline)
-        if m is None:
-            raise MalformedDocumentError(SecuredBMAEndpoint.API)
-        server = m.group(1)
-        ipv4 = m.group(2)
-        ipv6 = m.group(3)
-        port = int(m.group(4))
-        path = m.group(5)
-        if not path:
-            path = ""
-        return cls(server, ipv4, ipv6, port, path)
-
-    def inline(self):
-        inlined = [str(info) for info in (self.server, self.ipv4, self.ipv6, self.port, self.path) if info]
-        return SecuredBMAEndpoint.API + " " + " ".join(inlined)
-
-    def conn_handler(self, session: aiohttp.ClientSession = None, proxy: str = None) -> ConnectionHandler:
-        """
-        Return connection handler instance for the endpoint
-
-        :param aiohttp.ClientSession session: AIOHTTP client session instance
-        :param str proxy: Proxy url
-        :rtype: ConnectionHandler
-        """
-        if self.server:
-            return ConnectionHandler("https", "wss", self.server, self.port, self.path, proxy, session)
-        elif self.ipv6:
-            return ConnectionHandler("https", "wss", "[{0}]".format(self.ipv6), self.port, self.path, proxy, session)
-
-        return ConnectionHandler("https", "wss", self.ipv4, self.port, self.path, proxy, session)
-
-
-class WS2PEndpoint(Endpoint):
-    API = "WS2P"
-    re_inline = re.compile('^WS2P ({ws2pid_regex}) ((?:{host_regex})|(?:{ipv4_regex})) ([0-9]+)?(?: ({path_regex}))?$'.format(ws2pid_regex=ws2pid_regex,
-                                                                                                                 host_regex=host_regex,
-                                                                                                                 ipv4_regex=ipv4_regex,
-                                                                                                                 ipv6_regex=ipv6_regex,
-                                                                                                                 path_regex=path_regex))
-
-    def __init__(self, ws2pid, server, port, path):
-        self.ws2pid = ws2pid
-        self.server = server
-        self.port = port
-        self.path = path
-
-    @classmethod
-    def from_inline(cls, inline):
-        m = WS2PEndpoint.re_inline.match(inline)
-        if m is None:
-            raise MalformedDocumentError(WS2PEndpoint.API)
-        ws2pid = m.group(1)
-        server = m.group(2)
-        port = int(m.group(3))
-        path = m.group(4)
-        if not path:
-            path = ""
-        return cls(ws2pid, server, port, path)
-
-    def inline(self):
-        inlined = [str(info) for info in (self.ws2pid, self.server, self.port, self.path) if info]
-        return WS2PEndpoint.API + " " + " ".join(inlined)
-
-    def conn_handler(self, session: aiohttp.ClientSession = None, proxy: str = None) -> ConnectionHandler:
-        """
-        Return connection handler instance for the endpoint
-
-        :param aiohttp.ClientSession session: AIOHTTP client session instance
-        :param str proxy: Proxy url
-        :rtype: ConnectionHandler
-        """
-        return ConnectionHandler("https", "wss", self.server, self.port, self.path, proxy, session)
-
-    def __str__(self):
-        return self.inline()
-
-    def __eq__(self, other):
-        if isinstance(other, WS2PEndpoint):
-            return self.server == other.server and self.ws2pid == other.ws2pid \
-                    and self.port == other.port and self.path == other.path
-        else:
-            return False
-
-    def __hash__(self):
-        return hash((self.ws2pid, self.server, self.port, self.path))
-
-
-class ESUserEndpoint(Endpoint):
-    API = "ES_USER_API"
-    re_inline = re.compile('^ES_USER_API ((?:{host_regex})|(?:{ipv4_regex})) ([0-9]+)$'.format(ws2pid_regex=ws2pid_regex,
-                                                                                             host_regex=host_regex,
-                                                                                             ipv4_regex=ipv4_regex))
-
-    def __init__(self, server, port):
-        self.server = server
-        self.port = port
-
-    @classmethod
-    def from_inline(cls, inline):
-        m = ESUserEndpoint.re_inline.match(inline)
-        if m is None:
-            raise MalformedDocumentError(ESUserEndpoint.API)
-        server = m.group(1)
-        port = int(m.group(2))
-        return cls(server, port)
-
-    def inline(self):
-        inlined = [str(info) for info in (self.server, self.port) if info]
-        return ESUserEndpoint.API + " " + " ".join(inlined)
-
-    def conn_handler(self, session: aiohttp.ClientSession = None, proxy: str = None) -> ConnectionHandler:
-        """
-        Return connection handler instance for the endpoint
-
-        :param aiohttp.ClientSession session: AIOHTTP client session instance
-        :param str proxy: Proxy url
-        :rtype: ConnectionHandler
-        """
-        return ConnectionHandler("https", "wss", self.server, self.port, "", proxy, session)
-
-    def __str__(self):
-        return self.inline()
-
-    def __eq__(self, other):
-        if isinstance(other, ESUserEndpoint):
-            return self.server == other.server and self.port == other.port
-        else:
-            return False
-
-    def __hash__(self):
-        return hash((self.server, self.port))
-
-
-class ESSubscribtionEndpoint(Endpoint):
-    API = "ES_SUBSCRIPTION_API"
-    re_inline = re.compile('^ES_SUBSCRIPTION_API ((?:{host_regex})|(?:{ipv4_regex})) ([0-9]+)$'.format(ws2pid_regex=ws2pid_regex,
-                                                                                                      host_regex=host_regex,
-                                                                                                      ipv4_regex=ipv4_regex))
-
-    def __init__(self, server, port):
-        self.server = server
-        self.port = port
-
-    @classmethod
-    def from_inline(cls, inline):
-        m = ESSubscribtionEndpoint.re_inline.match(inline)
-        if m is None:
-            raise MalformedDocumentError(ESSubscribtionEndpoint.API)
-        server = m.group(1)
-        port = int(m.group(2))
-        return cls(server, port)
-
-    def inline(self):
-        inlined = [str(info) for info in (self.server, self.port) if info]
-        return ESSubscribtionEndpoint.API + " " + " ".join(inlined)
-
-    def conn_handler(self, session: aiohttp.ClientSession = None, proxy: str = None) -> ConnectionHandler:
-        """
-        Return connection handler instance for the endpoint
-
-        :param aiohttp.ClientSession session: AIOHTTP client session instance
-        :param str proxy: Proxy url
-        :rtype: ConnectionHandler
-        """
-        return ConnectionHandler("https", "wss", self.server, self.port, "", proxy, session)
-
-    def __str__(self):
-        return self.inline()
-
-    def __eq__(self, other):
-        if isinstance(other, ESSubscribtionEndpoint):
-            return self.server == other.server and self.port == other.port
-        else:
-            return False
-
-    def __hash__(self):
-        return hash((ESSubscribtionEndpoint.API, self.server, self.port))
-
-
-MANAGED_API = {
-    BMAEndpoint.API: BMAEndpoint,
-    SecuredBMAEndpoint.API: SecuredBMAEndpoint,
-    WS2PEndpoint.API: WS2PEndpoint,
-    ESUserEndpoint.API: ESUserEndpoint,
-    ESSubscribtionEndpoint.API: ESSubscribtionEndpoint
-}
diff --git a/examples/create_and_publish_identity.py b/examples/create_and_publish_identity.py
index b4fb846d6cafff1293c07c70e1bd278cd034a44f..60ba1d92ae4694b2d84a32084c5eca701d355151 100644
--- a/examples/create_and_publish_identity.py
+++ b/examples/create_and_publish_identity.py
@@ -3,7 +3,8 @@ import aiohttp
 import getpass
 
 import duniterpy.api.bma as bma
-from duniterpy.documents import BMAEndpoint, SecuredBMAEndpoint, BlockUID, Identity
+from duniterpy.api.endpoint import SecuredBMAEndpoint
+from duniterpy.documents import BlockUID, Identity
 from duniterpy.key import SigningKey
 
 
@@ -12,7 +13,7 @@ from duniterpy.key import SigningKey
 # 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)
-BMA_ENDPOINT = "BMAS g1-test.duniter.org 443"
+BMAS_ENDPOINT = "BMAS g1-test.duniter.org 443"
 
 # Your unique identifier in the Web of Trust
 UID = "MyIdentityTest"
@@ -63,7 +64,7 @@ async def main():
     """
 
     # connection handler from BMA endpoint
-    connection = SecuredBMAEndpoint.from_inline(BMA_ENDPOINT).conn_handler(AIOHTTP_SESSION)
+    connection = SecuredBMAEndpoint.from_inline(BMAS_ENDPOINT).conn_handler(AIOHTTP_SESSION)
     # capture current block to get version and currency and blockstamp
     current_block = await bma.blockchain.current(connection)
 
diff --git a/examples/request_data.py b/examples/request_data.py
index 87efed5f6b2b0dd12d99758e45c9e2bc9503add0..baac93dbeb0ff7a3131b17c7be6b3cfa4971d020 100644
--- a/examples/request_data.py
+++ b/examples/request_data.py
@@ -1,47 +1,47 @@
 import asyncio
-import aiohttp
-import duniterpy.api.bma as bma
-from duniterpy.documents import BMAEndpoint, SecuredBMAEndpoint
+from duniterpy.api.client import Client
+from duniterpy.api import bma
 
 # 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)
-BMA_ENDPOINT = "BMAS g1-test.duniter.org 443"
+BMAS_ENDPOINT = "BMAS g1-test.duniter.org 443"
 
 ################################################
 
-# Latest duniter-python-api is asynchronous and you have to create an aiohttp session to send request
-# ( http://pythonhosted.org/aiohttp )
-AIOHTTP_SESSION = aiohttp.ClientSession()
-
 
 async def main():
     """
     Main code
     """
-    # connection handler from BMA endpoint
-    connection = SecuredBMAEndpoint.from_inline(BMA_ENDPOINT).conn_handler(AIOHTTP_SESSION)
+    # Create Client from endpoint string in Duniter format
+    client = Client(BMAS_ENDPOINT)
+
+    # Get the node summary infos (direct REST GET request)
+    response = await client.get('node/summary')
+    print(response)
 
-    # Get the node summary infos
-    response = await bma.node.summary(connection)
+    # Get the node summary infos by dedicated method (with json schema validation)
+    response = await bma.node.summary(client)
     print(response)
 
-    # Get the current block data
-    response = await bma.blockchain.parameters(connection)
+    # Get the money parameters located in the first block
+    response = await bma.blockchain.parameters(client)
     print(response)
 
-    # Get the current block data
-    response = await bma.blockchain.current(connection)
+    # Get the current block
+    response = await bma.blockchain.current(client)
     print(response)
 
     # Get the block number 10
-    response = await bma.blockchain.block(connection, 10)
+    response = await bma.blockchain.block(client, 10)
     print(response)
 
-with AIOHTTP_SESSION:
+    # Close client aiohttp session
+    await client.close()
 
-    # 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())
+# 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/examples/save_revoke_document.py b/examples/save_revoke_document.py
index 1209db35237b233c67a004222f358d6b0ed816de..ae08e4121c1f2950ef2c3bb03578de3ca861a8f9 100644
--- a/examples/save_revoke_document.py
+++ b/examples/save_revoke_document.py
@@ -1,8 +1,8 @@
 import asyncio
 import aiohttp
 import duniterpy.api.bma as bma
-from duniterpy.documents import BMAEndpoint, SecuredBMAEndpoint, BlockUID, Identity
-from duniterpy.documents import Revocation
+from duniterpy.api.endpoint import SecuredBMAEndpoint
+from duniterpy.documents import Revocation, BlockUID, Identity
 from duniterpy.key import SigningKey
 import getpass
 import os
@@ -21,7 +21,7 @@ else:
 # 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)
-BMA_ENDPOINT = "BMAS g1-test.duniter.org 443"
+BMAS_ENDPOINT = "BMAS g1-test.duniter.org 443"
 
 # WARNING : Hide this file in a safe and secure place
 # If one day you forget your credentials,
@@ -39,7 +39,7 @@ async def get_identity_document(connection, currency, pubkey):
     """
     Get the Identity document of the pubkey
 
-    :param bma.api.ConnectionHandler connection: Connection handler
+    :param bma.connection.ConnectionHandler connection: Connection handler
     :param str currency: Currency name
     :param str pubkey: Public key
 
@@ -82,8 +82,8 @@ def get_revoke_document(identity, salt, password):
     :param str salt: Salt
     :param str password: Password
 
-    :return: the revokation document
-    :rtype: duniterpy.documents.certification.Revocation
+    :return: the raw signed revokation document
+    :rtype: str
     """
     document = Revocation(PROTOCOL_VERSION, identity.currency, identity.pubkey, "")
 
@@ -91,6 +91,7 @@ def get_revoke_document(identity, salt, password):
     document.sign(identity, [key])
     return document.signed_raw(identity)
 
+
 async def main():
     """
     Main code
@@ -113,7 +114,7 @@ async def main():
         exit(0)
 
     # connection handler from BMAS endpoint
-    connection = SecuredBMAEndpoint.from_inline(BMA_ENDPOINT).conn_handler(AIOHTTP_SESSION)
+    connection = SecuredBMAEndpoint.from_inline(BMAS_ENDPOINT).conn_handler(AIOHTTP_SESSION)
     # capture current block to get currency name
     current_block = await bma.blockchain.current(connection)
 
diff --git a/examples/send_certification.py b/examples/send_certification.py
index d31fb76590e4790754c71049d6b2bef2eb5f0d1e..1391a18960e6b5cbfb4fbdb5e7f87724810566c2 100644
--- a/examples/send_certification.py
+++ b/examples/send_certification.py
@@ -2,7 +2,8 @@ import asyncio
 import aiohttp
 import getpass
 import duniterpy.api.bma as bma
-from duniterpy.documents import BMAEndpoint, SecuredBMAEndpoint, BlockUID, Identity, Certification
+from duniterpy.api.endpoint import SecuredBMAEndpoint
+from duniterpy.documents import BlockUID, Identity, Certification
 from duniterpy.key import SigningKey
 
 
@@ -11,7 +12,7 @@ from duniterpy.key import SigningKey
 # 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)
-BMA_ENDPOINT = "BMAS g1-test.duniter.org 443"
+BMAS_ENDPOINT = "BMAS g1-test.duniter.org 443"
 
 ################################################
 
@@ -24,7 +25,7 @@ async def get_identity_document(connection, current_block, pubkey):
     """
     Get the identity document of the pubkey
 
-    :param bma.api.ConnectionHandler connection: Connection handler
+    :param bma.connection.ConnectionHandler connection: Connection handler
     :param dict current_block: Current block data
     :param str pubkey: UID/Public key
 
@@ -92,7 +93,7 @@ async def main():
     Main code
     """
     # connection handler from BMA endpoint
-    connection = SecuredBMAEndpoint.from_inline(BMA_ENDPOINT).conn_handler(AIOHTTP_SESSION)
+    connection = SecuredBMAEndpoint.from_inline(BMAS_ENDPOINT).conn_handler(AIOHTTP_SESSION)
 
     # prompt hidden user entry
     salt = getpass.getpass("Enter your passphrase (salt): ")
diff --git a/examples/send_membership.py b/examples/send_membership.py
index 790aa6a36ca6e7f8608d156626adbce0f01b83f7..7a85af848adafbf0679b291cc7dc7235cb96e203 100644
--- a/examples/send_membership.py
+++ b/examples/send_membership.py
@@ -3,7 +3,8 @@ import aiohttp
 import getpass
 
 import duniterpy.api.bma as bma
-from duniterpy.documents import BMAEndpoint, SecuredBMAEndpoint, BlockUID, Identity, Membership
+from duniterpy.api.endpoint import SecuredBMAEndpoint
+from duniterpy.documents import BlockUID, Identity, Membership
 from duniterpy.key import SigningKey
 
 
@@ -12,7 +13,7 @@ from duniterpy.key import SigningKey
 # 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)
-BMA_ENDPOINT = "BMAS g1-test.duniter.org 443"
+BMAS_ENDPOINT = "BMAS g1-test.duniter.org 443"
 
 ################################################
 
@@ -97,7 +98,7 @@ async def main():
     Main code
     """
     # connection handler from BMA endpoint
-    connection = SecuredBMAEndpoint.from_inline(BMA_ENDPOINT).conn_handler(AIOHTTP_SESSION)
+    connection = SecuredBMAEndpoint.from_inline(BMAS_ENDPOINT).conn_handler(AIOHTTP_SESSION)
 
     # capture current block to get version and currency and blockstamp
     current_block = await bma.blockchain.current(connection)
diff --git a/examples/send_transaction.py b/examples/send_transaction.py
index efd75736cbc06bbb227e701ccf92a7068282f6bf..98b6d9fe86909a174149ef7b840a05449b304ded 100644
--- a/examples/send_transaction.py
+++ b/examples/send_transaction.py
@@ -3,7 +3,8 @@ import getpass
 import aiohttp
 
 from duniterpy.api import bma
-from duniterpy.documents import BMAEndpoint, SecuredBMAEndpoint, BlockUID, Transaction
+from duniterpy.api.endpoint import SecuredBMAEndpoint
+from duniterpy.documents import BlockUID, Transaction
 from duniterpy.documents.transaction import InputSource, OutputSource, Unlock, SIGParameter
 from duniterpy.grammars.output import Condition, SIG
 from duniterpy.key import SigningKey
@@ -13,7 +14,7 @@ from duniterpy.key import SigningKey
 # 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)
-BMA_ENDPOINT = "BMAS g1-test.duniter.org 443"
+BMAS_ENDPOINT = "BMAS g1-test.duniter.org 443"
 
 
 ################################################
@@ -95,7 +96,7 @@ async def main():
     Main code
     """
     # connection handler from BMA endpoint
-    connection = SecuredBMAEndpoint.from_inline(BMA_ENDPOINT).conn_handler(AIOHTTP_SESSION)
+    connection = SecuredBMAEndpoint.from_inline(BMAS_ENDPOINT).conn_handler(AIOHTTP_SESSION)
 
     # prompt hidden user entry
     salt = getpass.getpass("Enter your passphrase (salt): ")
diff --git a/tests/api/bma/test_ws.py b/tests/api/bma/test_ws.py
index a7fcfca779605bc9bc3310d9e63970465233ed80..511c3623eaa06000bf8c8bba94c69a79e973ac9c 100644
--- a/tests/api/bma/test_ws.py
+++ b/tests/api/bma/test_ws.py
@@ -1,6 +1,6 @@
 import unittest
 from tests.api.webserver import WebFunctionalSetupMixin
-from duniterpy.api.bma.ws import block, peer, WS_BLOCk_SCHEMA, WS_PEER_SCHEMA
+from duniterpy.api.bma.ws import block, peer, WS_BLOCK_SCHEMA, WS_PEER_SCHEMA
 from duniterpy.api.bma import parse_text
 
 
@@ -81,7 +81,7 @@ class Test_BMA_Websocket(WebFunctionalSetupMixin, unittest.TestCase):
   "signature": "H41/8OGV2W4CLKbE35kk5t1HJQsb3jEM0/QGLUf80CwJvGZf3HvVCcNtHPUFoUBKEDQO9mPK3KJkqOoxHpqHCw=="
 }
 """
-        parse_text(json_sample, WS_BLOCk_SCHEMA)
+        parse_text(json_sample, WS_BLOCK_SCHEMA)
 
     def test_peer(self):
         json_sample = """{