diff --git a/duniterpy/api/client.py b/duniterpy/api/client.py
index 3bf6ae8e1adf43066f2ebce5b8811245a10712ad..da524ee6eacf6abb47cc188b8ff78e0cb0a639cf 100644
--- a/duniterpy/api/client.py
+++ b/duniterpy/api/client.py
@@ -94,6 +94,10 @@ def parse_response(response: str, schema: dict) -> Any:
         ) from exception
 
 
+class WSConnectionException(Exception):
+    pass
+
+
 class WSConnection:
     """
     Abstraction layer on websocket library
@@ -115,7 +119,7 @@ class WSConnection:
         :return:
         """
         if self.connection is None:
-            raise Exception("Connection property is empty")
+            raise WSConnectionException("Connection property is empty")
 
         self.connection.send(data)
 
@@ -127,7 +131,7 @@ class WSConnection:
         :return:
         """
         if self.connection is None:
-            raise Exception("Connection property is empty")
+            raise WSConnectionException("Connection property is empty")
         if timeout is not None:
             self.connection.settimeout(timeout)
         return self.connection.recv()
@@ -140,7 +144,7 @@ class WSConnection:
         :return:
         """
         if self.connection is None:
-            raise Exception("Connection property is empty")
+            raise WSConnectionException("Connection property is empty")
         if timeout is not None:
             self.connection.settimeout(timeout)
         return json.loads(self.connection.recv())
@@ -152,7 +156,7 @@ class WSConnection:
         :return:
         """
         if self.connection is None:
-            raise Exception("Connection property is empty")
+            raise WSConnectionException("Connection property is empty")
 
         self.connection.close()
 
diff --git a/duniterpy/api/ws2p/requests.py b/duniterpy/api/ws2p/requests.py
index 2ca9f166e77dd2705104ac65fa1e36f3daed1ce2..1935805d2ed439b7aa7f62abd2060755ab7c0bd9 100644
--- a/duniterpy/api/ws2p/requests.py
+++ b/duniterpy/api/ws2p/requests.py
@@ -173,6 +173,10 @@ REQUIREMENTS_RESPONSE_SCHEMA = {
 }
 
 
+class WS2PException(Exception):
+    pass
+
+
 def get_current(request_id: str) -> str:
     """
     Return ws2p getCurrent() request as json string
@@ -180,7 +184,7 @@ def get_current(request_id: str) -> str:
     :return:
     """
     if not re.fullmatch("^[0-9a-zA-Z]{8}$", request_id):
-        raise Exception("Invalid ws2p request unique id")
+        raise WS2PException("Invalid ws2p request unique id")
     return json.dumps({"reqId": request_id, "body": {"name": "CURRENT", "params": {}}})
 
 
@@ -191,7 +195,7 @@ def get_block(request_id: str, block_number: int) -> str:
     :return:
     """
     if not re.fullmatch("^[0-9a-zA-Z]{8}$", request_id):
-        raise Exception("Invalid ws2p request unique id")
+        raise WS2PException("Invalid ws2p request unique id")
     return json.dumps(
         {
             "reqId": request_id,
@@ -207,7 +211,7 @@ def get_blocks(request_id: str, from_number: int, count: int) -> str:
     :return:
     """
     if not re.fullmatch("^[0-9a-zA-Z]{8}$", request_id):
-        raise Exception("Invalid ws2p request unique id")
+        raise WS2PException("Invalid ws2p request unique id")
     return json.dumps(
         {
             "reqId": request_id,
@@ -226,7 +230,7 @@ def get_requirements_pending(request_id: str, min_cert: int) -> str:
     :return:
     """
     if not re.fullmatch("^[0-9a-zA-Z]{8}$", request_id):
-        raise Exception("Invalid ws2p request unique id")
+        raise WS2PException("Invalid ws2p request unique id")
     return json.dumps(
         {
             "reqId": request_id,
diff --git a/duniterpy/documents/block.py b/duniterpy/documents/block.py
index 3580159962dcfd0309effac90340e2d893ebc079..47921682c128a147713509625e0612e5e50a8a2c 100644
--- a/duniterpy/documents/block.py
+++ b/duniterpy/documents/block.py
@@ -35,6 +35,10 @@ BlockType = TypeVar("BlockType", bound="Block")
 VERSION = 12
 
 
+class SignatureException(Exception):
+    pass
+
+
 class Block(Document):
     """
     The class Block handles Block documents.
@@ -701,7 +705,7 @@ PreviousIssuer: {self.prev_issuer}\n"
         :return:
         """
         if self.signature is None:
-            raise Exception("Signature is None, can not verify signature")
+            raise SignatureException("Signature is None, can not verify signature")
 
         content_to_verify = f"InnerHash: {self.inner_hash}\nNonce: {self.nonce}\n"
         verifying_key = VerifyingKey(pubkey)
diff --git a/duniterpy/documents/document.py b/duniterpy/documents/document.py
index 4611980f2fbd50ab6d01dca6f26c9b7097e3f881..c0e85a232af049293f3e42b75be26adf6200bcb6 100644
--- a/duniterpy/documents/document.py
+++ b/duniterpy/documents/document.py
@@ -23,6 +23,10 @@ from ..constants import SIGNATURE_REGEX
 from ..key import SigningKey, VerifyingKey
 
 
+class SignatureException(Exception):
+    pass
+
+
 class MalformedDocumentError(Exception):
     """
     Malformed document exception
@@ -147,7 +151,9 @@ class Document:
         :return:
         """
         if self.signature is None:
-            raise Exception("Signature is not defined, can not check signature")
+            raise SignatureException(
+                "Signature is not defined, can not check signature"
+            )
 
         verifying_key = VerifyingKey(pubkey)
 
diff --git a/duniterpy/documents/identity.py b/duniterpy/documents/identity.py
index 1437320c44a7618e7d1756ab4f428239242cf2a8..923322d9fffb924b1c71a885ccc4cc58e9216350 100644
--- a/duniterpy/documents/identity.py
+++ b/duniterpy/documents/identity.py
@@ -34,6 +34,10 @@ IdentityType = TypeVar("IdentityType", bound="Identity")
 VERSION = 10
 
 
+class IdentityException(Exception):
+    pass
+
+
 class Identity(Document):
     """
     A document describing a self certification.
@@ -315,6 +319,6 @@ Timestamp: {self.block_id}\n"
                 identity.signature = signature
 
         if identity is None:
-            raise Exception("Identity pubkey not found")
+            raise IdentityException("Identity pubkey not found")
 
         return identity
diff --git a/duniterpy/documents/transaction.py b/duniterpy/documents/transaction.py
index cc7bcbfb878afe11f67f22b7c05e4267f4a0b2f2..7c7afeb586b35a271a5655bd3ca79643e10d93ae 100644
--- a/duniterpy/documents/transaction.py
+++ b/duniterpy/documents/transaction.py
@@ -455,6 +455,10 @@ class Unlock:
         return f"{self.index}:{params}"
 
 
+class SignatureException(Exception):
+    pass
+
+
 # required to type hint cls in classmethod
 TransactionType = TypeVar("TransactionType", bound="Transaction")
 
@@ -953,13 +957,15 @@ Currency: {self.currency}\n"
         :return:
         """
         if not self.signatures:
-            raise Exception("No signatures, can not check signatures")
+            raise SignatureException("No signatures, can not check signatures")
 
         if isinstance(pubkeys, str):
             pubkeys = [pubkeys]
 
         if len(self.signatures) != len(pubkeys):
-            raise Exception("Number of pubkeys not equal to number of signatures")
+            raise SignatureException(
+                "Number of pubkeys not equal to number of signatures"
+            )
 
         content_to_verify = self.raw()
 
diff --git a/duniterpy/key/crc_pubkey.py b/duniterpy/key/crc_pubkey.py
index 810553bef80df5629837ad1d6b45edbcab625bd3..f30028046b3d245496150e95810530852f98be83 100644
--- a/duniterpy/key/crc_pubkey.py
+++ b/duniterpy/key/crc_pubkey.py
@@ -26,6 +26,10 @@ from duniterpy.tools import ensure_str
 CRCPubkeyType = TypeVar("CRCPubkeyType", bound="CRCPubkey")
 
 
+class CRCPubkeyException(Exception):
+    pass
+
+
 class CRCPubkey:
     """
     Class to implement a crc on a pubkey
@@ -53,7 +57,7 @@ class CRCPubkey:
         """
         data = CRCPubkey.re_crc_pubkey.match(crc_pubkey)
         if data is None:
-            raise Exception(f"Could not parse CRC public key {crc_pubkey}")
+            raise CRCPubkeyException(f"Could not parse CRC public key {crc_pubkey}")
         pubkey = data.group(1)
         crc = data.group(2)
         return cls(pubkey, crc)
diff --git a/duniterpy/key/signing_key.py b/duniterpy/key/signing_key.py
index f825164ee2aaa9f7ef0ea388b90e8ae11f94d5d6..95f23ad21a863d5966e1819546c150fdc9d35f83 100644
--- a/duniterpy/key/signing_key.py
+++ b/duniterpy/key/signing_key.py
@@ -41,6 +41,10 @@ def opener_user_rw(path, flags):
     return os.open(path, flags, 0o600)
 
 
+class SigningKeyException(Exception):
+    pass
+
+
 class SigningKey(libnacl.sign.Signer):
     def __init__(self, seed: bytes) -> None:
         """
@@ -136,7 +140,7 @@ class SigningKey(libnacl.sign.Signer):
         regex_seedhex = re.compile("([0-9a-fA-F]{64})")
         match = re.search(regex_seedhex, seedhex)
         if not match:
-            raise Exception("Error: Bad seed hexadecimal format")
+            raise SigningKeyException("Error: Bad seed hexadecimal format")
         seedhex = match.groups()[0]
         seed = convert_seedhex_to_seed(seedhex)
         return cls(seed)
@@ -194,12 +198,16 @@ class SigningKey(libnacl.sign.Signer):
         # check public key field
         match = re.search(regex_pubkey, pubsec_content)
         if not match:
-            raise Exception("Error: Bad format PubSec v1 file, missing public key")
+            raise SigningKeyException(
+                "Error: Bad format PubSec v1 file, missing public key"
+            )
 
         # check signkey field
         match = re.search(regex_signkey, pubsec_content)
         if not match:
-            raise Exception("Error: Bad format PubSec v1 file, missing sec key")
+            raise SigningKeyException(
+                "Error: Bad format PubSec v1 file, missing sec key"
+            )
 
         # capture signkey
         signkey_hex = match.groups()[0]
@@ -246,7 +254,7 @@ sec: {base58_signing_key}"
         regex = re.compile("Data: ([1-9A-HJ-NP-Za-km-z]+)", re.MULTILINE)
         match = re.search(regex, wif_content)
         if not match:
-            raise Exception("Error: Bad format WIF or EWIF v1 file")
+            raise SigningKeyException("Error: Bad format WIF or EWIF v1 file")
 
         # capture hexa wif key
         wif_hex = match.groups()[0]
@@ -271,7 +279,7 @@ sec: {base58_signing_key}"
         elif fi == b"\x02" and password is not None:
             result = SigningKey.from_ewif_hex(wif_hex, password)
         else:
-            raise Exception("Error: Bad format: not WIF nor EWIF")
+            raise SigningKeyException("Error: Bad format: not WIF nor EWIF")
 
         return result
 
@@ -289,7 +297,7 @@ sec: {base58_signing_key}"
         regex = re.compile("Data: ([1-9A-HJ-NP-Za-km-z]+)", re.MULTILINE)
         match = re.search(regex, wif_content)
         if not match:
-            raise Exception("Error: Bad format WIF v1 file")
+            raise SigningKeyException("Error: Bad format WIF v1 file")
 
         # capture hexa wif key
         wif_hex = match.groups()[0]
@@ -304,7 +312,7 @@ sec: {base58_signing_key}"
         """
         wif_bytes = Base58Encoder.decode(wif_hex)
         if len(wif_bytes) != 35:
-            raise Exception("Error: the size of WIF is invalid")
+            raise SigningKeyException("Error: the size of WIF is invalid")
 
         # extract data
         checksum_from_wif = wif_bytes[-2:]
@@ -314,12 +322,12 @@ sec: {base58_signing_key}"
 
         # check WIF format flag
         if fi != b"\x01":
-            raise Exception("Error: bad format version, not WIF")
+            raise SigningKeyException("Error: bad format version, not WIF")
 
         # checksum control
         checksum = libnacl.crypto_hash_sha256(libnacl.crypto_hash_sha256(seed_fi))[0:2]
         if checksum_from_wif != checksum:
-            raise Exception("Error: bad checksum of the WIF")
+            raise SigningKeyException("Error: bad checksum of the WIF")
 
         return cls(seed)
 
@@ -364,7 +372,7 @@ Data: {wif_key}"
         regex = re.compile("Data: ([1-9A-HJ-NP-Za-km-z]+)", re.MULTILINE)
         match = re.search(regex, wif_content)
         if not match:
-            raise Exception("Error: Bad format EWIF v1 file")
+            raise SigningKeyException("Error: Bad format EWIF v1 file")
 
         # capture ewif key
         ewif_hex = match.groups()[0]
@@ -382,7 +390,7 @@ Data: {wif_key}"
         """
         ewif_bytes = Base58Encoder.decode(ewif_hex)
         if len(ewif_bytes) != 39:
-            raise Exception("Error: the size of EWIF is invalid")
+            raise SigningKeyException("Error: the size of EWIF is invalid")
 
         # extract data
         fi = ewif_bytes[0:1]
@@ -394,14 +402,14 @@ Data: {wif_key}"
 
         # check format flag
         if fi != b"\x02":
-            raise Exception("Error: bad format version, not EWIF")
+            raise SigningKeyException("Error: bad format version, not EWIF")
 
         # checksum control
         checksum = libnacl.crypto_hash_sha256(
             libnacl.crypto_hash_sha256(ewif_no_checksum)
         )[0:2]
         if checksum_from_ewif != checksum:
-            raise Exception("Error: bad checksum of the EWIF")
+            raise SigningKeyException("Error: bad checksum of the EWIF")
 
         # SCRYPT
         password_bytes = password.encode("utf-8")
@@ -425,7 +433,7 @@ Data: {wif_key}"
             libnacl.crypto_hash_sha256(Base58Encoder.decode(signer.pubkey))
         )[0:4]
         if salt_from_seed != salt:
-            raise Exception("Error: bad Password of EWIF address")
+            raise SigningKeyException("Error: bad Password of EWIF address")
 
         return cls(seed)
 
@@ -496,7 +504,7 @@ Data: {ewif_key}"
         )
         match = re.search(regex, ssb_content)
         if not match:
-            raise Exception("Error: Bad scuttlebutt secret file")
+            raise SigningKeyException("Error: Bad scuttlebutt secret file")
 
         # capture ssb secret key
         secret = match.groups()[1]