diff --git a/network-documents/src/network_documents.pest b/network-documents/src/network_documents.pest
index 9cf01d409d8f1cd3bd22670ac172cb0fcf6e73cd..5461807299b8949616d2d5c7312cd65de0d80761 100644
--- a/network-documents/src/network_documents.pest
+++ b/network-documents/src/network_documents.pest
@@ -78,19 +78,22 @@ peer_v11 = ${ "11:" ~ currency ~ ":" ~ node_id ~ ":" ~ pubkey ~ ":" ~ blockstamp
 api_outgoing_conf = @{ u8 }
 api_incoming_conf = @{ u8 }
 free_member_rooms = @{ u8 }
-low_priority_rooms = @{ u8 }
+free_mirror_rooms = @{ u8 }
 software = @{ ASCII_ALPHA ~ ASCII_ALPHANUMERIC* }
-soft_version = @{ ASCII_DIGIT ~ "." ~ ASCII_DIGIT ~ "." ~ ASCII_DIGIT ~ ("-" ~ ("a" | "b" | "rc") ~ ASCII_DIGIT ~ (ASCII_DIGIT ~ "."){0,2})? }
+soft_version = @{ ASCII_DIGIT ~ "." ~ ASCII_DIGIT ~ "." ~ ASCII_DIGIT ~ ("-" ~ ("a" | "b" | "rc") ~ ASCII_DIGIT ~ ("." ~ ASCII_DIGIT){0,2})? }
+step = @{ u_int }
 
-head_v3_body = ${
+head_v3 = ${
+    "3:" ~ currency ~ ":" ~
     api_outgoing_conf ~ ":" ~
     api_incoming_conf ~ ":" ~
     free_member_rooms ~ ":" ~
-    low_priority_rooms ~ ":" ~
+    free_mirror_rooms ~ ":" ~
     node_id ~ ":" ~
     pubkey ~ ":" ~
     blockstamp ~ ":" ~
     software ~ ":" ~
-    soft_version
+    soft_version ~ nl ~
+    ed25519_sig? ~
+    (nl ~ step)?
 }
-
diff --git a/network-documents/src/network_head.rs b/network-documents/src/network_head.rs
index 5f6d2979299109836ba086004bad7243efd54622..396e977ce73795786dafd2920957ef0d5ce06ce0 100644
--- a/network-documents/src/network_head.rs
+++ b/network-documents/src/network_head.rs
@@ -32,7 +32,7 @@ pub enum NetworkHead {
     /// Head V2
     V2(Box<NetworkHeadV2>),
     /// head V3
-    V3(Box<NetworkHeadV3Container>),
+    V3(Box<NetworkHeadV3>),
 }
 
 impl ToString for NetworkHead {
diff --git a/network-documents/src/network_head_v3.rs b/network-documents/src/network_head_v3.rs
index 25251ff5334093f41bcf449b13db563c6f62c27e..e9998fe2db72f1a68f5e5ac0ed7828dc92b7c15d 100644
--- a/network-documents/src/network_head_v3.rs
+++ b/network-documents/src/network_head_v3.rs
@@ -17,68 +17,27 @@
 
 use base58::ToBase58;
 use duniter_documents::blockstamp::Blockstamp;
-use dup_crypto::keys::bin_signable::BinSignable;
+use duniter_documents::{BlockHash, BlockId, CurrencyName, ToJsonObject};
+use dup_crypto::keys::text_signable::TextSignable;
 use dup_crypto::keys::*;
-use serde_json;
+use pest::iterators::Pair;
+use pest::Parser;
 use std::cmp::Ordering;
-use NodeId;
-
-#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
-/// Head V3
-pub struct NetworkHeadV3Container {
-    /// Head step
-    pub step: u8,
-    /// head body
-    pub body: NetworkHeadV3,
-}
-
-impl PartialOrd for NetworkHeadV3Container {
-    fn partial_cmp(&self, other: &NetworkHeadV3Container) -> Option<Ordering> {
-        Some(self.cmp(other))
-    }
-}
-
-impl Ord for NetworkHeadV3Container {
-    fn cmp(&self, other: &NetworkHeadV3Container) -> Ordering {
-        self.body.cmp(&other.body)
-    }
-}
-
-impl NetworkHeadV3Container {
-    /// Convert to JSON String
-    pub fn to_json_head(&self) -> Result<String, serde_json::Error> {
-        Ok(serde_json::to_string_pretty(&JsonHeadV3 {
-            api_outgoing_conf: self.body.api_outgoing_conf,
-            api_incoming_conf: self.body.api_incoming_conf,
-            free_mirror_rooms: self.body.free_mirror_rooms,
-            low_priority_rooms: self.body.low_priority_rooms,
-            node_id: self.body.node_id,
-            algorithm: self.body.pubkey.algo(),
-            pubkey: self.body.pubkey.to_base58(),
-            blockstamp: self.body.blockstamp.to_string(),
-            software: &self.body.software,
-            soft_version: &self.body.soft_version,
-            signature: if let Some(sig) = self.body.signature {
-                Some(sig.to_base64())
-            } else {
-                None
-            },
-            step: self.step,
-        })?)
-    }
-}
+use *;
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
 /// Head V3
 pub struct NetworkHeadV3 {
+    /// Currency name
+    pub currency_name: CurrencyName,
     /// WS2P Private configuration
     pub api_outgoing_conf: u8,
     /// WS2P Public configuration
     pub api_incoming_conf: u8,
+    /// Issuer node free member rooms
+    pub free_member_rooms: u8,
     /// Issuer node free mirror rooms
     pub free_mirror_rooms: u8,
-    /// Issuer node free "low priority" rooms
-    pub low_priority_rooms: u8,
     /// Issuer node id
     pub node_id: NodeId,
     /// Issuer pubkey
@@ -91,6 +50,8 @@ pub struct NetworkHeadV3 {
     pub soft_version: String,
     /// Issuer signature
     pub signature: Option<Sig>,
+    /// Head step
+    pub step: u8,
 }
 
 impl PartialOrd for NetworkHeadV3 {
@@ -105,7 +66,7 @@ impl Ord for NetworkHeadV3 {
     }
 }
 
-impl<'de> BinSignable<'de> for NetworkHeadV3 {
+/*impl<'de> BinSignable<'de> for NetworkHeadV3 {
     fn issuer_pubkey(&self) -> PubKey {
         self.pubkey
     }
@@ -115,19 +76,122 @@ impl<'de> BinSignable<'de> for NetworkHeadV3 {
     fn set_signature(&mut self, signature: Sig) {
         self.signature = Some(signature);
     }
+}*/
+
+impl TextSignable for NetworkHeadV3 {
+    fn as_signable_text(&self) -> String {
+        format!(
+"3:{currency}:{api_outgoing_conf}:{api_incoming_conf}:{free_member_rooms}:{free_mirror_rooms}:{node_id}:{pubkey}:{blockstamp}:{software}:{soft_version}\n",
+            currency = self.currency_name,
+            api_outgoing_conf = self.api_outgoing_conf,
+            api_incoming_conf = self.api_incoming_conf,
+            free_member_rooms = self.free_member_rooms,
+            free_mirror_rooms = self.free_mirror_rooms,
+            node_id = format!("{}", self.node_id),
+            pubkey = self.pubkey.to_base58(),
+            blockstamp = self.blockstamp.to_string(),
+            software = self.software,
+            soft_version = self.soft_version,
+        )
+    }
+    fn issuer_pubkey(&self) -> PubKey {
+        self.pubkey
+    }
+    fn signature(&self) -> Option<Sig> {
+        self.signature
+    }
+    fn set_signature(&mut self, signature: Sig) {
+        self.signature = Some(signature);
+    }
+}
+
+impl NetworkHeadV3 {
+    /// parse from raw ascii format
+    pub fn parse_from_raw(raw_peer: &str) -> Result<NetworkHeadV3, ParseError> {
+        match NetworkDocsParser::parse(Rule::head_v3, raw_peer) {
+            Ok(mut head_v3_pairs) => {
+                Ok(NetworkHeadV3::from_pest_pair(head_v3_pairs.next().unwrap()))
+            }
+            Err(pest_error) => Err(ParseError::PestError(format!("{}", pest_error))),
+        }
+    }
+    /// Generate from pest pair
+    fn from_pest_pair(pair: Pair<Rule>) -> NetworkHeadV3 {
+        let mut currency_str = "";
+        let mut api_outgoing_conf = 0;
+        let mut api_incoming_conf = 0;
+        let mut free_member_rooms = 0;
+        let mut free_mirror_rooms = 0;
+        let mut node_id = NodeId(0);
+        let mut pubkey = None;
+        let mut blockstamp = None;
+        let mut software = "";
+        let mut soft_version = "";
+        let mut signature = None;
+        let mut step = 0;
+        for field in pair.into_inner() {
+            match field.as_rule() {
+                Rule::currency => currency_str = field.as_str(),
+                Rule::api_outgoing_conf => api_outgoing_conf = field.as_str().parse().unwrap(),
+                Rule::api_incoming_conf => api_incoming_conf = field.as_str().parse().unwrap(),
+                Rule::free_member_rooms => free_member_rooms = field.as_str().parse().unwrap(),
+                Rule::free_mirror_rooms => free_mirror_rooms = field.as_str().parse().unwrap(),
+                Rule::node_id => node_id = NodeId(field.as_str().parse().unwrap()),
+                Rule::pubkey => {
+                    pubkey = Some(PubKey::Ed25519(
+                        ed25519::PublicKey::from_base58(field.as_str()).unwrap(),
+                    ))
+                }
+                Rule::blockstamp => {
+                    let mut inner_rules = field.into_inner(); // { block_id ~ "-" ~ hash }
+
+                    let block_id: &str = inner_rules.next().unwrap().as_str();
+                    let block_hash: &str = inner_rules.next().unwrap().as_str();
+                    blockstamp = Some(Blockstamp {
+                        id: BlockId(block_id.parse().unwrap()), // Grammar ensures that we have a digits string.
+                        hash: BlockHash(Hash::from_hex(block_hash).unwrap()), // Grammar ensures that we have an hexadecimal string.
+                    });
+                }
+                Rule::software => software = field.as_str(),
+                Rule::soft_version => soft_version = field.as_str(),
+                Rule::ed25519_sig => {
+                    signature = Some(Sig::Ed25519(
+                        ed25519::Signature::from_base64(field.as_str()).unwrap(),
+                    ))
+                }
+                Rule::step => step = field.as_str().parse().unwrap(),
+                _ => panic!("unexpected rule: {:?}", field.as_rule()), // Grammar ensures that we never reach this line
+            }
+        }
+        NetworkHeadV3 {
+            currency_name: CurrencyName(currency_str.to_owned()),
+            api_outgoing_conf,
+            api_incoming_conf,
+            free_member_rooms,
+            free_mirror_rooms,
+            node_id,
+            pubkey: pubkey.expect("Grammar must ensure that head v3 have valid issuer pubkey !"),
+            blockstamp: blockstamp
+                .expect("Grammar must ensure that head v3 have valid blockstamp!"),
+            software: software.to_owned(),
+            soft_version: soft_version.to_owned(),
+            signature,
+            step,
+        }
+    }
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
 /// Head V3 for json serializer
-pub struct JsonHeadV3<'a> {
+pub struct JsonHeadV3 {
     /// WS2P Private configuration
     pub api_outgoing_conf: u8,
     /// WS2P Public configuration
     pub api_incoming_conf: u8,
+    /// Issuer node free member rooms
+    pub free_member_rooms: u8,
     /// Issuer node free mirror rooms
     pub free_mirror_rooms: u8,
-    /// Issuer node free "low priority" rooms
-    pub low_priority_rooms: u8,
     /// Issuer node id
     pub node_id: NodeId,
     /// Issuer key algorithm
@@ -137,57 +201,77 @@ pub struct JsonHeadV3<'a> {
     /// Head blockstamp
     pub blockstamp: String,
     /// Issuer node software
-    pub software: &'a str,
+    pub software: String,
     /// Issuer node soft version
-    pub soft_version: &'a str,
+    pub soft_version: String,
     /// Issuer signature
     pub signature: Option<String>,
     /// Head step
     pub step: u8,
 }
 
+impl<'a> ToJsonObject for NetworkHeadV3 {
+    type JsonObject = JsonHeadV3;
+
+    fn to_json_object(&self) -> Self::JsonObject {
+        JsonHeadV3 {
+            api_outgoing_conf: self.api_outgoing_conf,
+            api_incoming_conf: self.api_incoming_conf,
+            free_member_rooms: self.free_member_rooms,
+            free_mirror_rooms: self.free_mirror_rooms,
+            node_id: self.node_id,
+            algorithm: self.pubkey.algo(),
+            pubkey: self.pubkey.to_base58(),
+            blockstamp: self.blockstamp.to_string(),
+            software: self.software.clone(),
+            soft_version: self.soft_version.clone(),
+            signature: if let Some(sig) = self.signature {
+                Some(sig.to_base64())
+            } else {
+                None
+            },
+            step: self.step,
+        }
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
-    use dup_crypto::keys::bin_signable::BinSignable;
-    use tests::bincode::deserialize;
     use tests::keypair1;
 
     #[test]
     fn head_v3_sign_and_verify() {
-        let mut head_v3 = NetworkHeadV3Container {
+        let keypair = keypair1();
+        let mut head_v3 = NetworkHeadV3 {
+            currency_name: CurrencyName("g1".to_owned()),
+            api_outgoing_conf: 0u8,
+            api_incoming_conf: 0u8,
+            free_mirror_rooms: 0u8,
+            free_member_rooms: 0u8,
+            node_id: NodeId(0),
+            pubkey: PubKey::Ed25519(keypair.public_key()),
+            blockstamp: Blockstamp::from_string(
+                "50-000005B1CEB4EC5245EF7E33101A330A1C9A358EC45A25FC13F78BB58C9E7370",
+            )
+            .unwrap(),
+            software: String::from("durs"),
+            soft_version: String::from("0.1.0-a0.1"),
+            signature: None,
             step: 0,
-            body: NetworkHeadV3 {
-                api_outgoing_conf: 0u8,
-                api_incoming_conf: 0u8,
-                free_mirror_rooms: 0u8,
-                low_priority_rooms: 0u8,
-                node_id: NodeId(0),
-                pubkey: PubKey::Ed25519(keypair1().public_key()),
-                blockstamp: Blockstamp::from_string(
-                    "50-000005B1CEB4EC5245EF7E33101A330A1C9A358EC45A25FC13F78BB58C9E7370",
-                )
-                .unwrap(),
-                software: String::from("durs"),
-                soft_version: String::from("0.1.0-a0.1"),
-                signature: None,
-            },
         };
         // Sign
-        let sign_result = head_v3
-            .body
-            .sign(PrivKey::Ed25519(keypair1().private_key()));
-        if let Ok(head_v3_body_bytes) = sign_result {
-            let deser_head_v3_body: NetworkHeadV3 =
-                deserialize(&head_v3_body_bytes).expect("Fail to deserialize PeerCardV11 !");
-            assert_eq!(head_v3.body, deser_head_v3_body,)
+        let sign_result = head_v3.sign(PrivKey::Ed25519(keypair.private_key()));
+        if let Ok(head_v3_raw) = sign_result {
+            println!("{}", head_v3_raw);
+            assert_eq!(
+                head_v3,
+                NetworkHeadV3::parse_from_raw(&head_v3_raw).expect("Fail to parse head v3 !")
+            )
         } else {
-            panic!("failt to sign head v3 : {:?}", sign_result.err().unwrap())
+            panic!("fail to sign head v3 : {:?}", sign_result.err().unwrap())
         }
         // Verify signature
-        head_v3.body.verify().expect("HEADv3 : Invalid signature !");
-        //let json_head_v3 = head_v3.to_json_head().expect("Fail to serialize HEAD v3 !");
-        //println!("{}", json_head_v3);
-        //panic!();
+        head_v3.verify().expect("HEADv3 : Invalid signature !");
     }
 }
diff --git a/ws2p-messages/v2/payload_container.rs b/ws2p-messages/v2/payload_container.rs
index af62ee4d93eb5a9158bbbffe6d03e80d8ca11cf9..8bf5cfd89778dfb5a8a5a9477edb8d6686ab80f8 100644
--- a/ws2p-messages/v2/payload_container.rs
+++ b/ws2p-messages/v2/payload_container.rs
@@ -26,7 +26,7 @@ use duniter_documents::v10::revocation::RevocationDocument;
 use duniter_documents::v10::transaction::TransactionDocument;
 use dup_crypto::hashs::Hash;
 use durs_network_documents::network_head_v2::NetworkHeadV2;
-use durs_network_documents::network_head_v3::NetworkHeadV3Container;
+use durs_network_documents::network_head_v3::NetworkHeadV3;
 use durs_network_documents::network_peer::PeerCardV11;
 
 /// WS2P v2 message payload metadata size
@@ -54,7 +54,7 @@ pub enum WS2Pv0MessagePayload {
     /// HEADS_V2 Message
     Headsv2(Vec<NetworkHeadV2>),
     /// HEADS_V3 Message
-    Heads3(Vec<NetworkHeadV3Container>),
+    Heads3(Vec<NetworkHeadV3>),
     /// BLOCKS Message
     Blocks(Vec<BlockDocument>),
     /// PENDING_IDENTITIES Message