diff --git a/end2end-tests/README.md b/end2end-tests/README.md
index 6bea5535161d2e486fc8cae70415ae783728139b..96556e6e74be9d2793bd221895c8157361d26790 100644
--- a/end2end-tests/README.md
+++ b/end2end-tests/README.md
@@ -81,14 +81,22 @@ List of possible actions:
 
 ### Test users
 
-6 test users are provided:
-
-- alice
-- bob
-- charlie
-- dave
-- eve
-- ferdie
+8 test users are provided derived from the same [dev mnemonic](https://docs.substrate.io/v3/getting-started/glossary/#dev-phrase)
+
+```
+bottom drive obey lake curtain smoke basket hold race lonely fit walk
+```
+
+with the derivation path `//Alice`, `//Bob`...
+
+- alice `5GrwvaEF5zXb26Fz9rcQpDWS57CtERHpNehXCPcNoHGKutQY`
+- bob `5FHneW46xGXgs5mUiveU4sbTyGBzmstUspZC92UhjJM694ty`
+- charlie `5FLSigC9HGRKVhB9FiEo4Y3koPsNmBmLJbpXg2mp1hXcS59Y`
+- dave `5DAAnrj7VHTznn2AWBemMuyBwZWs6FNFjdyVXUeYum3PTXFy`
+- eve `5HGjWAeFDfFCWPsjFQdVV2Msvz2XtMktvgocEZcCj68kUMaw`
+- ferdie `5CiPPseXPECbkjWCa6MnjNokrgYjMqmKndv2rSnekmSK2DjL`
+- one `5Fxune7f71ZbpP2FoY3mhYcmM596Erhv1gRue4nsPwkxMR4n`
+- two `5CUjxa4wVKMj3FqKdqAUf7zcEMr4MYAjXeWmUf44B41neLmJ`
 
 ### Currency amounts
 
diff --git a/end2end-tests/cucumber-features/identity_creation.feature b/end2end-tests/cucumber-features/identity_creation.feature
index d0398b3b6cc8ac965e66d274eeb46ebe133e8c9d..dbfae873a7c2970fc8aceb92f43f001c6be31fcd 100644
--- a/end2end-tests/cucumber-features/identity_creation.feature
+++ b/end2end-tests/cucumber-features/identity_creation.feature
@@ -1,5 +1,6 @@
 Feature: Identity creation
 
   Scenario: alice invites a new member to join the web of trust
-    When alice creates identity for roumoulou
-    Then roumoulou identity should be created
+    When alice creates identity for ferdie
+    When 2 block later
+    Then ferdie identity should be created
diff --git a/end2end-tests/tests/common/identity.rs b/end2end-tests/tests/common/identity.rs
new file mode 100644
index 0000000000000000000000000000000000000000..3057e6ec6fd16a05bdb917a9c07f79ffdbab174d
--- /dev/null
+++ b/end2end-tests/tests/common/identity.rs
@@ -0,0 +1,43 @@
+// Copyright 2021 Axiom-Team
+//
+// This file is part of Substrate-Libre-Currency.
+//
+// Substrate-Libre-Currency is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as published by
+// the Free Software Foundation, version 3 of the License.
+//
+// Substrate-Libre-Currency 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 Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with Substrate-Libre-Currency. If not, see <https://www.gnu.org/licenses/>.
+
+use super::node_runtime::runtime_types::gdev_runtime;
+use super::node_runtime::runtime_types::pallet_identity;
+use super::*;
+use sp_keyring::AccountKeyring;
+use subxt::{sp_runtime::MultiAddress, PairSigner};
+
+pub async fn create_identity(
+    api: &Api,
+    client: &Client,
+    from: AccountKeyring,
+    to: AccountKeyring,
+) -> Result<()> {
+    let from = PairSigner::new(from.pair());
+    let to = to.to_account_id();
+
+    let _events = create_block_with_extrinsic(
+        client,
+        api.tx()
+            .identity()
+            .create_identity(to)
+            .create_signed(&from, ())
+            .await?,
+    )
+    .await?;
+
+    Ok(())
+}
diff --git a/end2end-tests/tests/common/mod.rs b/end2end-tests/tests/common/mod.rs
index c3d53e9d6b1010f2dee2977c781dec2c97fcf3bc..20c657d16e9ddd29e38856c6ca508df81ec2e87e 100644
--- a/end2end-tests/tests/common/mod.rs
+++ b/end2end-tests/tests/common/mod.rs
@@ -18,6 +18,7 @@
 
 pub mod balances;
 pub mod cert;
+pub mod identity;
 
 #[subxt::subxt(runtime_metadata_path = "../resources/metadata.scale")]
 pub mod node_runtime {}
diff --git a/end2end-tests/tests/cucumber_tests.rs b/end2end-tests/tests/cucumber_tests.rs
index 13d88217d7109f84ca59248c49f00e3f865d78f4..d3eb60893d9b9d00fc7e78714cd2bdaf8ba12e93 100644
--- a/end2end-tests/tests/cucumber_tests.rs
+++ b/end2end-tests/tests/cucumber_tests.rs
@@ -199,6 +199,15 @@ async fn certifies(world: &mut DuniterWorld, from: String, to: String) -> Result
     common::cert::certify(world.api(), world.client(), from, to).await
 }
 
+#[when(regex = r"([a-zA-Z]+) creates identity for ([a-zA-Z]+)")]
+async fn creates_identity(world: &mut DuniterWorld, from: String, to: String) -> Result<()> {
+    // Parse inputs
+    let from = AccountKeyring::from_str(&from).expect("unknown from");
+    let to = AccountKeyring::from_str(&to).expect("unknown to");
+
+    common::identity::create_identity(world.api(), world.client(), from, to).await
+}
+
 // ===== then ====
 
 #[then(regex = r"([a-zA-Z]+) should have (\d+) (ÄžD|cÄžD)")]
@@ -263,6 +272,7 @@ async fn should_be_certified_by(
         .expect("unknown to")
         .to_account_id();
 
+    // get corresponding identities index
     let issuer_index = world
         .api()
         .storage()
@@ -278,6 +288,8 @@ async fn should_be_certified_by(
         .await?
         .unwrap();
 
+    // look for certification by issuer/receiver pair
+    // note: panics if certification does not exist
     let _certification = world
         .api()
         .storage()
@@ -289,6 +301,38 @@ async fn should_be_certified_by(
     Ok(())
 }
 
+#[then(regex = r"([a-zA-Z]+) identity should be created")]
+async fn identity_should_be_created(world: &mut DuniterWorld, receiver: String) -> Result<()> {
+    // Parse inputs
+    let receiver_account = AccountKeyring::from_str(&receiver)
+        .expect("unknown to")
+        .to_account_id();
+
+    let receiver_index = world
+        .api()
+        .storage()
+        .identity()
+        .identity_index_of(receiver_account, None)
+        .await?
+        .ok_or_else(|| anyhow::anyhow!("identity {} has no associated index", receiver))
+        .unwrap();
+
+    let _identity_value = world
+        .api()
+        .storage()
+        .identity()
+        .identities(receiver_index, None)
+        .await?
+        .ok_or_else(|| {
+            anyhow::anyhow!(
+                "indentity index {} does not have associated value",
+                receiver_index
+            )
+        })?;
+
+    Ok(())
+}
+
 // ============================================================
 
 #[derive(clap::Args)]