diff --git a/tools/deploy b/tools/deploy
index 18b6209a..b57acf57 100755
--- a/tools/deploy
+++ b/tools/deploy
@@ -1,6 +1,6 @@
 #!/usr/bin/env python
 
-from typing import Any, List
+from typing import Any, List, Dict, Callable
 
 import os
 import sys
@@ -11,6 +11,7 @@ import requests
 import urllib
 import json
 from urllib import parse
+from requests import Response
 
 red = '\033[91m'  # type: str
 green = '\033[92m'  # type: str
@@ -71,6 +72,35 @@ def check_common_options(options: argparse.Namespace) -> None:
         print('tools/deploy: Botfarm deploy token not specified.')
         sys.exit(1)
 
+def handle_common_response_without_data(response: Response,
+                                        operation: str,
+                                        success_message: str) -> bool:
+    return handle_common_response(
+        response=response,
+        operation=operation,
+        success_handler=lambda r: print('{}: {}'.format(operation, success_message))
+    )
+
+def handle_common_response(response: Response,
+                           operation: str,
+                           success_handler: Callable[[Dict[str, Any]], Any]) -> bool:
+    if response.status_code == requests.codes.ok:
+        response_data = response.json()
+        if response_data['status'] == 'success':
+            success_handler(response_data)
+            return True
+        elif response_data['status'] == 'error':
+            print('{}: {}'.format(operation, response_data['message']))
+            return False
+        else:
+            print('{}: Unexpected success response format'.format(operation))
+            return False
+    if response.status_code == requests.codes.unauthorized:
+        print('{}: Authentication error with the server. Aborting.'.format(operation))
+    else:
+        print('{}: Error {}. Aborting.'.format(operation, response.status_code))
+    return False
+
 def upload(options: argparse.Namespace) -> None:
     check_common_options(options)
     file_path = os.path.join(bots_dir, options.botname + '.zip')
@@ -80,15 +110,10 @@ def upload(options: argparse.Namespace) -> None:
     files = {'file': open(file_path, 'rb')}
     headers = {'key': options.key}
     url = urllib.parse.urljoin(options.server, 'bots/upload')
-    r = requests.post(url, files=files, headers=headers)
-    if r.status_code == requests.codes.ok:
-        print('upload: Uploaded the bot package to botfarm.')
-        return
-    if r.status_code == 401:
-        print('upload: Authentication error with the server. Aborting.')
-    else:
-        print('upload: Error {}. Aborting.'.format(r.status_code))
-    sys.exit(1)
+    response = requests.post(url, files=files, headers=headers)
+    result = handle_common_response_without_data(response, 'upload', 'Uploaded the bot package to botfarm.')
+    if result is False:
+        sys.exit(1)
 
 def clean(options: argparse.Namespace) -> None:
     file_path = os.path.join(bots_dir, options.botname + '.zip')
@@ -103,45 +128,30 @@ def process(options: argparse.Namespace) -> None:
     headers = {'key': options.key}
     url = urllib.parse.urljoin(options.server, 'bots/process')
     payload = {'name': options.botname}
-    r = requests.post(url, headers=headers, json=payload)
-    if r.status_code == requests.codes.ok and r.text == 'done':
-        print('process: The bot has been processed by the botfarm.')
-        return
-    if r.status_code == 401:
-        print('process: Authentication error with the server. Aborting.')
-    else:
-        print('process: Error {}: {}. Aborting.'.format(r.status_code, r.text))
-    sys.exit(1)
+    response = requests.post(url, headers=headers, json=payload)
+    result = handle_common_response_without_data(response, 'process', 'The bot has been processed by the botfarm.')
+    if result is False:
+        sys.exit(1)
 
 def start(options: argparse.Namespace) -> None:
     check_common_options(options)
     headers = {'key': options.key}
     url = urllib.parse.urljoin(options.server, 'bots/start')
     payload = {'name': options.botname}
-    r = requests.post(url, headers=headers, json=payload)
-    if r.status_code == requests.codes.ok and r.text == 'done':
-        print('start: The bot has been started by the botfarm.')
-        return
-    if r.status_code == 401:
-        print('start: Authentication error with the server. Aborting.')
-    else:
-        print('start: Error {}: {}. Aborting.'.format(r.status_code, r.text))
-    sys.exit(1)
+    response = requests.post(url, headers=headers, json=payload)
+    result = handle_common_response_without_data(response, 'start', 'The bot has been started by the botfarm.')
+    if result is False:
+        sys.exit(1)
 
 def stop(options: argparse.Namespace) -> None:
     check_common_options(options)
     headers = {'key': options.key}
     url = urllib.parse.urljoin(options.server, 'bots/stop')
     payload = {'name': options.botname}
-    r = requests.post(url, headers=headers, json=payload)
-    if r.status_code == requests.codes.ok and r.text == 'done':
-        print('stop: The bot has been stopped by the botfarm.')
-        return
-    if r.status_code == 401:
-        print('stop: Authentication error with the server. Aborting.')
-    else:
-        print('stop: Error {}: {}. Aborting.'.format(r.status_code, r.text))
-    sys.exit(1)
+    response = requests.post(url, headers=headers, json=payload)
+    result = handle_common_response_without_data(response, 'stop', 'The bot has been stopped by the botfarm.')
+    if result is False:
+        sys.exit(1)
 
 def prepare(options: argparse.Namespace) -> None:
     pack(options)
@@ -158,30 +168,20 @@ def log(options: argparse.Namespace) -> None:
         lines = None
     payload = {'name': options.botname, 'lines': lines}
     url = urllib.parse.urljoin(options.server, 'bots/logs/' + options.botname)
-    r = requests.get(url, json=payload, headers=headers)
-    if r.status_code == requests.codes.ok:
-        print(r.text)
-        return
-    if r.status_code == 401:
-        print('log: Authentication error with the server. Aborting.')
-    else:
-        print('log: Error {}: {}. Aborting.'.format(r.status_code, r.text))
-    sys.exit(1)
+    response = requests.get(url, json=payload, headers=headers)
+    result = handle_common_response(response, 'log', lambda r: print(r['logs']['content']))
+    if result is False:
+        sys.exit(1)
 
 def delete(options: argparse.Namespace) -> None:
     check_common_options(options)
     headers = {'key': options.key}
     url = urllib.parse.urljoin(options.server, 'bots/delete')
     payload = {'name': options.botname}
-    r = requests.post(url, headers=headers, json=payload)
-    if r.status_code == requests.codes.ok and r.text == 'done':
-        print('delete: The bot has been removed from the botfarm.')
-        return
-    if r.status_code == 401:
-        print('delete: Authentication error with the server. Aborting.')
-    else:
-        print('delete: Error {}: {}. Aborting.'.format(r.status_code, r.text))
-    sys.exit(1)
+    response = requests.post(url, headers=headers, json=payload)
+    result = handle_common_response_without_data(response, 'delete', 'The bot has been removed from the botfarm.')
+    if result is False:
+        sys.exit(1)
 
 def list_bots(options: argparse.Namespace) -> None:
     check_common_options(options)
@@ -191,17 +191,10 @@ def list_bots(options: argparse.Namespace) -> None:
     else:
         pretty_print = False
     url = urllib.parse.urljoin(options.server, 'bots/list')
-    r = requests.get(url, headers=headers)
-    if r.status_code == requests.codes.ok:
-        data = json.loads(r.text)
-        if 'bots' in data:
-            print_bots(data['bots'], pretty_print)
-            return
-    if r.status_code == 401:
-        print('ls: Authentication error with the server. Aborting.')
-    else:
-        print('ls: Error {}: {}. Aborting.'.format(r.status_code, r.text))
-    sys.exit(1)
+    response = requests.get(url, headers=headers)
+    result = handle_common_response(response, 'ls', lambda r: print_bots(r['bots']['list'], pretty_print))
+    if result is False:
+        sys.exit(1)
 
 def print_bots(bots: List[Any], pretty_print: bool) -> None:
     if pretty_print: