diff --git a/README.md b/README.md
index d61e05acbcfa6e061d58371be128d40d98f0482e..fe5035fad89adf98c65391da6961578e876a3a2a 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,6 @@ It is currently used by following programs:
 - [websocket-client](https://pypi.org/project/websocket-client)
 - [jsonschema](https://pypi.org/project/jsonschema)
 - [pyPEG2](https://pypi.org/project/pyPEG2)
-- [attrs](https://pypi.org/project/attrs)
 - [base58](https://pypi.org/project/base58)
 - [libnacl](https://pypi.org/project/libnacl)
 - [pyaes](https://pypi.org/project/pyaes)
diff --git a/duniterpy/documents/ws2p/heads.py b/duniterpy/documents/ws2p/heads.py
index 9f6a3ec491829cd3fda415afe3b98693636ae47c..05da42e3dec981fc7260c125c1d263d47430c72f 100644
--- a/duniterpy/documents/ws2p/heads.py
+++ b/duniterpy/documents/ws2p/heads.py
@@ -14,9 +14,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import re
-
-import attr
-import attrs
+from dataclasses import dataclass
 
 from ...constants import (
     BLOCK_ID_REGEX,
@@ -32,10 +30,10 @@ from ..block_id import BlockID
 from ..document import MalformedDocumentError
 
 
-@attr.s()
+@dataclass
 class API:
-    private = attr.ib(type=str)
-    public = attr.ib(type=str)
+    private: str
+    public: str
 
     re_inline = re.compile(
         f"WS2P({WS2P_PRIVATE_PREFIX_REGEX})?({WS2P_PUBLIC_PREFIX_REGEX})?"
@@ -54,9 +52,9 @@ class API:
         return f"WS2P{self.private}{self.public}"
 
 
-@attr.s()
+@dataclass
 class Head:
-    version = attr.ib(type=int)
+    version: int
 
     re_inline = re.compile(WS2P_HEAD_REGEX)
 
@@ -76,13 +74,13 @@ class Head:
         return "HEAD" if self.version == 0 else f"HEAD:{str(self.version)}"
 
 
-@attr.s()
+@dataclass
 class HeadV0(Head):
-    signature = attr.ib(type=str)
-    api = attr.ib(type=API)
-    head = attr.ib(type=Head)
-    pubkey = attr.ib(type=str)
-    block_id = attr.ib(type=BlockID)
+    signature: str
+    api: API
+    head: Head
+    pubkey: str
+    block_id: BlockID
 
     re_inline = re.compile(
         f"^(WS2P(?:{WS2P_PRIVATE_PREFIX_REGEX})?(?:{WS2P_PUBLIC_PREFIX_REGEX})?):\
@@ -107,19 +105,7 @@ class HeadV0(Head):
             raise MalformedDocumentError("HeadV0") from AttributeError
 
     def inline(self) -> str:
-        values = (
-            str(v)
-            for v in attrs.astuple(
-                self,
-                recurse=False,
-                filter=attrs.filters.exclude(
-                    attrs.fields(HeadV0).version,
-                    attrs.fields(HeadV0).signature,
-                    attrs.fields(HeadV0).api,
-                ),
-            )
-        )
-        return f'{str(self.api)}:{":".join(values)}'
+        return f"{str(self.api)}:{str(self.head)}:{self.pubkey}:{str(self.block_id)}"
 
     def check_signature(self, pubkey: str) -> bool:
         """
@@ -133,12 +119,12 @@ class HeadV0(Head):
         return verifying_key.check_signature(self.inline(), self.signature)
 
 
-@attr.s()
+@dataclass
 class HeadV1(HeadV0):
-    ws2pid = attr.ib(type=str)
-    software = attr.ib(type=str)
-    software_version = attr.ib(type=str)
-    pow_prefix = attr.ib(type=int)
+    ws2pid: str
+    software: str
+    software_version: str
+    pow_prefix: int
 
     re_inline = re.compile(
         "({ws2pid}):({software}):({software_version}):({pow_prefix})(?::)?(.*)".format(
@@ -179,11 +165,14 @@ class HeadV1(HeadV0):
         except AttributeError:
             raise MalformedDocumentError("HeadV1") from AttributeError
 
+    def inline(self) -> str:
+        return f"{super().inline()}:{self.ws2pid}:{self.software}:{self.software_version}:{self.pow_prefix}"
+
 
-@attr.s
+@dataclass
 class HeadV2(HeadV1):
-    free_member_room = attr.ib(type=int)
-    free_mirror_room = attr.ib(type=int)
+    free_member_room: int
+    free_mirror_room: int
 
     re_inline = re.compile(
         "({free_member_room}):({free_mirror_room})(?::)?(.*)".format(
@@ -219,3 +208,6 @@ class HeadV2(HeadV1):
             )
         except AttributeError:
             raise MalformedDocumentError("HeadV2") from AttributeError
+
+    def inline(self) -> str:
+        return f"{super().inline()}:{self.free_member_room}:{self.free_mirror_room}"
diff --git a/pyproject.toml b/pyproject.toml
index e76f67e193e16f5cf0fa30ffc9d6c010ae16376f..d1934a72cc112df293bcc16cc5c3fbd15b7f4179 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -31,7 +31,6 @@ graphql-core = "^3.2.3"
 websocket-client = "^1.5.2"
 jsonschema = "^4.17.3"
 pypeg2 = "^2.15.2"
-attrs = "^23.1.0"
 base58 = "^2.1.1"
 libnacl = "^1.8.0"
 pyaes = "^1.6.1"