diff --git a/silkaj/auth.py b/silkaj/auth.py
index 8e84672e17a94bf4bdb5f99ab81db7af1cef1e50..c62ff0ffca717f79b522caf793108d5d65e6bd58 100644
--- a/silkaj/auth.py
+++ b/silkaj/auth.py
@@ -14,7 +14,6 @@
 # along with Silkaj. If not, see <https://www.gnu.org/licenses/>.
 
 import re
-import sys
 from pathlib import Path
 from typing import Optional
 
@@ -166,7 +165,8 @@ def auth_by_auth_file(ctx: click.Context, authfile: Path) -> SigningKey:
     # PubSec format
     if re.search(regex_pubkey, filetxt) and re.search(regex_signkey, filetxt):
         return SigningKey.from_pubsec_file(authfile)
-    sys.exit("Error: the format of the file is invalid")
+    tools.click_fail("The format of the file is invalid")
+    return None
 
 
 def auth_by_seed() -> SigningKey:
@@ -196,10 +196,10 @@ def auth_by_scrypt(ctx: click.Context, nrp: Optional[str]) -> SigningKey:
         if a.isnumeric() and b.isnumeric() and c.isnumeric():
             n, r, p = int(a), int(b), int(c)
             if n <= 0 or n > 65536 or r <= 0 or r > 512 or p <= 0 or p > 32:
-                sys.exit("Error: the values of Scrypt parameters are not good")
+                tools.click_fail("The values of Scrypt parameters are not good")
             scrypt_params = ScryptParams(n, r, p)
         else:
-            sys.exit("one of n, r or p is not a number")
+            tools.click_fail("one of n, r or p is not a number")
     else:
         scrypt_params = None
 
diff --git a/silkaj/checksum.py b/silkaj/checksum.py
index bc9e3f8d911a4e402924103f74ed9fbf7fc538af..592ab38e97d29e17c46ff81e0bcc3ebcac957413 100644
--- a/silkaj/checksum.py
+++ b/silkaj/checksum.py
@@ -14,7 +14,6 @@
 # along with Silkaj. If not, see <https://www.gnu.org/licenses/>.
 
 import re
-import sys
 
 import rich_click as click
 
@@ -40,7 +39,7 @@ def checksum_command(pubkey_checksum: str) -> None:
         key = auth.auth_method()
         click.echo(gen_pubkey_checksum(key.pubkey))
     elif not pubkey_checksum:
-        sys.exit(MESSAGE)
+        tools.click_fail(MESSAGE)
     elif re.search(re.compile(PUBKEY_DELIMITED_PATTERN), pubkey_checksum[0]):
         click.echo(gen_pubkey_checksum(pubkey_checksum[0]))
     elif re.search(re.compile(PUBKEY_CHECKSUM_PATTERN), pubkey_checksum[0]):
@@ -50,4 +49,4 @@ def checksum_command(pubkey_checksum: str) -> None:
         else:
             click.echo("The checksum is invalid")
     else:
-        sys.exit("Error: Wrong public key format")
+        tools.click_fail("Wrong public key format")
diff --git a/silkaj/cli.py b/silkaj/cli.py
index 3fef5fca29e576127cdc1a125406cc6876a56b84..2eff376563aa98640d56f8e0561ec32849a76dd4 100644
--- a/silkaj/cli.py
+++ b/silkaj/cli.py
@@ -14,7 +14,6 @@
 # along with Silkaj. If not, see <https://www.gnu.org/licenses/>.
 
 import contextlib
-import sys
 
 import rich_click as click
 from duniterpy.api.endpoint import endpoint as du_endpoint
@@ -120,7 +119,7 @@ def cli(
     dry_run: bool,
 ) -> None:
     if display and dry_run:
-        sys.exit("ERROR: display and dry-run options can not be used together")
+        ctx.fail("Display and dry-run options can not be used together")
 
     ctx.obj = {}
     ctx.ensure_object(dict)
diff --git a/silkaj/money/balance.py b/silkaj/money/balance.py
index e1159906b81016172aab94b1cf7b360155acf02e..6a69ccfedc57c974f4db4f063b0a07d01e16b142 100644
--- a/silkaj/money/balance.py
+++ b/silkaj/money/balance.py
@@ -13,7 +13,6 @@
 # You should have received a copy of the GNU Affero General Public License
 # along with Silkaj. If not, see <https://www.gnu.org/licenses/>.
 
-import sys
 from typing import Optional
 
 import rich_click as click
@@ -33,7 +32,7 @@ def balance_cmd(ctx: click.Context, pubkeys: str) -> None:
     if not tools.has_account_defined(exit_error=False):
         # check input pubkeys
         if not pubkeys:
-            sys.exit("You should specify one or many pubkeys")
+            ctx.fail("You should specify one or many pubkeys")
         pubkeys_list = []
         wrong_pubkeys = False
         for input_pubkey in pubkeys:
@@ -43,14 +42,14 @@ def balance_cmd(ctx: click.Context, pubkeys: str) -> None:
             else:
                 pubkey = input_pubkey
                 wrong_pubkeys = True
-                print(f"ERROR: pubkey {pubkey} has a wrong format")
+                click.echo(f"ERROR: pubkey {pubkey} has a wrong format")
             if pubkey in pubkeys_list:
-                sys.exit(
-                    f"ERROR: pubkey {gen_pubkey_checksum(pubkey)} was specified many times",
+                ctx.fail(
+                    f"Pubkey {gen_pubkey_checksum(pubkey)} was specified many times",
                 )
             pubkeys_list.append(pubkey)
         if wrong_pubkeys:
-            sys.exit("Please check the pubkeys format.")
+            ctx.fail("Please check the pubkeys format reported above.")
 
         total = [0, 0]
         for pubkey in pubkeys_list:
diff --git a/silkaj/network.py b/silkaj/network.py
index 6365fe34bb3fc43374c1f0a833b1b51a12c7c42d..2d476ff73da9139941557a8bf66c354c3848e698 100644
--- a/silkaj/network.py
+++ b/silkaj/network.py
@@ -24,7 +24,7 @@ from duniterpy.api import endpoint as ep
 from duniterpy.api.client import Client
 from duniterpy.documents import Document
 
-from silkaj import constants
+from silkaj import constants, tools
 
 
 def determine_endpoint() -> ep.Endpoint:
@@ -52,10 +52,10 @@ def determine_endpoint() -> ep.Endpoint:
     if endpoint:
         m = re.search(re.compile(regex), endpoint)
         if not m:
-            sys.exit(
-                "Error: Passed endpoint is of wrong format.\n\
-Expected format: {host|ipv4|[ipv6]}:{port}{/path}",
+            tools.click_fail(
+                "Passed endpoint is of wrong format. Expected format: {host|ipv4|[ipv6]}:{port}{/path}",
             )
+            return None
         port = int(m["port"]) if m["port"] else 443
         host, ipv4 = ep.fix_host_ipv4_mix_up(m["host"], m["ipv4"])
 
@@ -81,7 +81,7 @@ def send_document(bma_path: Any, document: Document) -> None:
         print(f"{doc_name} successfully sent")
     except HTTPError as error:
         print(error)
-        sys.exit(f"Error while publishing {doc_name.lower()}")
+        tools.click_fail(f"Error while publishing {doc_name.lower()}")
 
 
 def exit_on_http_error(error: HTTPError, err_code: int, message: str) -> None:
@@ -90,6 +90,6 @@ def exit_on_http_error(error: HTTPError, err_code: int, message: str) -> None:
     Else, displays the HTTP error message.
     """
     if error.code == err_code:
-        sys.exit(message)
+        tools.click_fail(message)
     print(error)
     sys.exit(constants.FAILURE_EXIT_STATUS)
diff --git a/silkaj/wot/exclusions.py b/silkaj/wot/exclusions.py
index d0e864b6b69a65ce99efb49669e79d062b1447b4..2cf8c256478ee4d7717815d35a8cc2cd386cb6c7 100644
--- a/silkaj/wot/exclusions.py
+++ b/silkaj/wot/exclusions.py
@@ -112,7 +112,7 @@ def check_options(api_id, duniter_forum_api_key, ml_forum_api_key, publish, curr
         or (not ml_forum_api_key and currency != dp_const.G1_TEST_CURRENCY_CODENAME)
     ):
         sys.exit(
-            "Error: To be able to publish, api_id, duniter_forum_api, and \
+            f"Error: To be able to publish, api_id, duniter_forum_api, and \
 ml_forum_api_key (not required for {constants.GTEST_SYMBOL}) options should be specified",
         )
 
diff --git a/silkaj/wot/membership.py b/silkaj/wot/membership.py
index 2da7efeb56c5045075cf05e8a96e667771523bc7..4dfed3b0f36e28a6bdf2dbdea8389c4999299439 100644
--- a/silkaj/wot/membership.py
+++ b/silkaj/wot/membership.py
@@ -14,7 +14,6 @@
 # along with Silkaj. If not, see <https://www.gnu.org/licenses/>.
 
 import logging
-import sys
 
 import arrow
 import rich_click as click
@@ -24,7 +23,7 @@ from duniterpy.key import SigningKey
 
 from silkaj import auth, tui
 from silkaj.blockchain import tools as bc_tools
-from silkaj.constants import DATE, SUCCESS_EXIT_STATUS
+from silkaj.constants import DATE
 from silkaj.g1_monetary_license import license_approval
 from silkaj.network import client_instance, send_document
 from silkaj.public_key import gen_pubkey_checksum
@@ -33,7 +32,7 @@ from silkaj.wot import tools as w_tools
 
 @click.command(
     "membership",
-    help="Send and sign membership document: \n\
+    help="Send and sign membership document:\n\
 for first emission and for renewal",
 )
 @click.pass_context
@@ -74,7 +73,7 @@ def send_membership(ctx: click.Context) -> None:
 
     if dry_run:
         click.echo(membership.signed_raw())
-        sys.exit(SUCCESS_EXIT_STATUS)
+        ctx.exit()
 
     if ctx.obj["DISPLAY_DOCUMENT"]:
         click.echo(membership.signed_raw())
diff --git a/tests/unit/money/test_tools.py b/tests/unit/money/test_tools.py
index 318024d71fe455cd685395838530a242279dc8bf..883481fe528cd194ca3bb48923c0420fca6861e1 100644
--- a/tests/unit/money/test_tools.py
+++ b/tests/unit/money/test_tools.py
@@ -168,8 +168,8 @@ def test_balance_errors():
         ],
     )
     pubkeyCk = gen_pubkey_checksum("BFb5yv8z1fowR6Z8mBXTALy5z7gHfMU976WtXhmRsUMh")
-    assert f"ERROR: pubkey {pubkeyCk} was specified many times" in result.output
-    assert result.exit_code == FAILURE_EXIT_STATUS
+    assert f"Pubkey {pubkeyCk} was specified many" in result.output
+    assert result.exit_code >= FAILURE_EXIT_STATUS
 
     # wrong pubkey
     result = CliRunner().invoke(
@@ -180,10 +180,10 @@ def test_balance_errors():
             "B",
         ],
     )
-    assert "ERROR: pubkey B has a wrong format" in result.output
-    assert result.exit_code == FAILURE_EXIT_STATUS
+    assert "pubkey B has a wrong format" in result.output
+    assert result.exit_code >= FAILURE_EXIT_STATUS
 
     # no pubkey
     result = CliRunner().invoke(cli, ["money", "balance"])
     assert "You should specify one or many pubkeys" in result.output
-    assert result.exit_code == FAILURE_EXIT_STATUS
+    assert result.exit_code >= FAILURE_EXIT_STATUS
diff --git a/tests/unit/test_checksum.py b/tests/unit/test_checksum.py
index 4223a49a3e07db79a4201b99bbb52c84df3782a7..798952694a925e78362972a126a1754a59910831 100644
--- a/tests/unit/test_checksum.py
+++ b/tests/unit/test_checksum.py
@@ -38,7 +38,7 @@ def patched_auth_method_test():
         (["checksum", pubkey_checksum], "The checksum is valid"),
         (["checksum", f"{pubkey}:vAK"], "The checksum is invalid"),
         (["checksum", pubkey], pubkey_checksum),
-        (["checksum", "uid"], "Error: Wrong public key format"),
+        (["checksum", "uid"], "Wrong public key format"),
         (["checksum"], MESSAGE),
         (["--account", account, "checksum"], pubkey_checksum),
         (["--account", account, "checksum", "pubkey"], pubkey_checksum),
@@ -47,4 +47,4 @@ def patched_auth_method_test():
 def test_checksum_command(command, excepted_output, monkeypatch):
     monkeypatch.setattr(auth, "auth_method", patched_auth_method_test)
     result = CliRunner().invoke(cli, args=command)
-    assert result.output == f"{excepted_output}\n"
+    assert excepted_output in result.output
diff --git a/tests/unit/test_cli.py b/tests/unit/test_cli.py
index 32e538d5e669198c98ef6e20fe81b4fa68f20ef6..626b4f214bdfeffeaf985d567630331efbc3c642 100644
--- a/tests/unit/test_cli.py
+++ b/tests/unit/test_cli.py
@@ -15,8 +15,8 @@
 
 from click.testing import CliRunner
 
+from silkaj import constants
 from silkaj.cli import cli
-from silkaj.constants import FAILURE_EXIT_STATUS
 
 
 def test_cli_dry_run_display_options_passed_together():
@@ -24,6 +24,5 @@ def test_cli_dry_run_display_options_passed_together():
     command = ["--dry-run", "--display", "wot", "membership"]
     result = CliRunner().invoke(cli, args=command)
 
-    error_msg = "ERROR: display and dry-run options can not be used together\n"
-    assert error_msg == result.output
-    assert result.exit_code == FAILURE_EXIT_STATUS
+    assert "Display and dry-run options can not be used together" in result.output
+    assert result.exit_code >= constants.FAILURE_EXIT_STATUS
diff --git a/tests/unit/wot/test_revocation.py b/tests/unit/wot/test_revocation.py
index c6deb82939502acc3768b8439a23385b444a623c..a82c93ecf849bb775e30ac63bca074cdc7936351 100644
--- a/tests/unit/wot/test_revocation.py
+++ b/tests/unit/wot/test_revocation.py
@@ -594,7 +594,7 @@ def test_revocation_cli_publish_send_errors(
         result = runner.invoke(cli, args=command, input=user_input)
         for expect in expected:
             assert expect in result.output
-        assert result.exit_code == FAILURE_EXIT_STATUS
+        assert result.exit_code >= FAILURE_EXIT_STATUS
 
 
 # test cli revoke
@@ -724,7 +724,7 @@ def test_revocation_cli_revoke_errors(display, user_input, doc, expected, monkey
     result = CliRunner().invoke(cli, args=command, input=user_input)
     for expect in expected:
         assert expect in result.output
-    assert result.exit_code == FAILURE_EXIT_STATUS
+    assert result.exit_code >= FAILURE_EXIT_STATUS
 
 
 # test create_revocation_doc