diff --git a/lib/ansible/module_utils/network/fortios/fortios.py b/lib/ansible/module_utils/network/fortios/fortios.py
index bf3385aa31b..879921bbd94 100644
--- a/lib/ansible/module_utils/network/fortios/fortios.py
+++ b/lib/ansible/module_utils/network/fortios/fortios.py
@@ -4,7 +4,8 @@
 # still belong to the author of the module, and may assign their own license
 # to the complete work.
 #
-# Copyright (c), Benjamin Jolivot <bjolivot@gmail.com>, 2014
+# Copyright (c), Benjamin Jolivot <bjolivot@gmail.com>, 2014,
+# Miguel Angel Munoz <magonzalez@fortinet.com>, 2019
 # All rights reserved.
 #
 # Redistribution and use in source and binary forms, with or without modification,
@@ -33,6 +34,9 @@ import traceback
 from ansible.module_utils._text import to_native
 from ansible.module_utils.basic import env_fallback
 
+import json
+
+# BEGIN DEPRECATED
 
 # check for pyFG lib
 try:
@@ -72,6 +76,105 @@ fortios_error_codes = {
     '-61': "Command error"
 }
 
+# END DEPRECATED
+
+
+class FortiOSHandler(object):
+
+    def __init__(self, conn):
+        self._conn = conn
+
+    def cmdb_url(self, path, name, vdom=None, mkey=None):
+
+        url = '/api/v2/cmdb/' + path + '/' + name
+        if mkey:
+            url = url + '/' + str(mkey)
+        if vdom:
+            if vdom == "global":
+                url += '?global=1'
+            else:
+                url += '?vdom=' + vdom
+        return url
+
+    def schema(self, path, name, vdom=None):
+        if vdom is None:
+            url = self.cmdb_url(path, name) + "?action=schema"
+        else:
+            url = self.cmdb_url(path, name, vdom=vdom) + "&action=schema"
+
+        status, result_data = self._conn.send_request(url=url)
+
+        if status == 200:
+            if vdom == "global":
+                return json.loads(result_data.decode('utf-8'))[0]['results']
+            else:
+                return json.loads(result_data.decode('utf-8'))['results']
+        else:
+            return json.loads(result_data.decode('utf-8'))
+
+    def get_mkeyname(self, path, name, vdom=None):
+        schema = self.schema(path, name, vdom=vdom)
+        try:
+            keyname = schema['mkey']
+        except KeyError:
+            return False
+        return keyname
+
+    def get_mkey(self, path, name, data, vdom=None):
+
+        keyname = self.get_mkeyname(path, name, vdom)
+        if not keyname:
+            return None
+        else:
+            try:
+                mkey = data[keyname]
+            except KeyError:
+                return None
+        return mkey
+
+    def set(self, path, name, data, mkey=None, vdom=None, parameters=None):
+
+        if not mkey:
+            mkey = self.get_mkey(path, name, data, vdom=vdom)
+        url = self.cmdb_url(path, name, vdom, mkey)
+
+        status, result_data = self._conn.send_request(url=url, params=parameters, data=json.dumps(data), method='PUT')
+
+        if status == 404 or status == 405 or status == 500:
+            return self.post(path, name, data, vdom, mkey)
+        else:
+            return self.formatresponse(result_data, vdom=vdom)
+
+    def post(self, path, name, data, vdom=None,
+             mkey=None, parameters=None):
+
+        if mkey:
+            mkeyname = self.get_mkeyname(path, name, vdom)
+            data[mkeyname] = mkey
+
+        url = self.cmdb_url(path, name, vdom, mkey=None)
+
+        status, result_data = self._conn.send_request(url=url, params=parameters, data=json.dumps(data), method='POST')
+
+        return self.formatresponse(result_data, vdom=vdom)
+
+    def delete(self, path, name, vdom=None, mkey=None, parameters=None, data=None):
+        if not mkey:
+            mkey = self.get_mkey(path, name, data, vdom=vdom)
+        url = self.cmdb_url(path, name, vdom, mkey)
+        status, result_data = self._conn.send_request(url=url, params=parameters, data=json.dumps(data), method='DELETE')
+        return self.formatresponse(result_data, vdom=vdom)
+
+    def formatresponse(self, res, vdom=None):
+        if vdom == "global":
+            resp = json.loads(res.decode('utf-8'))[0]
+            resp['vdom'] = "global"
+        else:
+            resp = json.loads(res.decode('utf-8'))
+        return resp
+
+# BEGIN DEPRECATED
+
 
 def backup(module, running_config):
     backup_path = module.params['backup_path']
@@ -198,3 +301,5 @@ class AnsibleFortios(object):
 
     def get_empty_configuration_block(self, block_name, block_type):
         return FortiConfig(block_name, block_type)
+
+# END DEPRECATED
diff --git a/lib/ansible/plugins/httpapi/fortios.py b/lib/ansible/plugins/httpapi/fortios.py
new file mode 100644
index 00000000000..7c40dd89ce8
--- /dev/null
+++ b/lib/ansible/plugins/httpapi/fortios.py
@@ -0,0 +1,125 @@
+# This code is part of Ansible, but is an independent component.
+# This particular file snippet, and this file snippet only, is BSD licensed.
+# Modules you write using this snippet, which is embedded dynamically by Ansible
+# still belong to the author of the module, and may assign their own license
+# to the complete work.
+#
+# (c) 2019 Fortinet, Inc
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without modification,
+# are permitted provided that the following conditions are met:
+#
+#    * Redistributions of source code must retain the above copyright
+#      notice, this list of conditions and the following disclaimer.
+#    * Redistributions in binary form must reproduce the above copyright notice,
+#      this list of conditions and the following disclaimer in the documentation
+#      and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+# INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+# USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+from __future__ import (absolute_import, division, print_function)
+__metaclass__ = type
+
+DOCUMENTATION = """
+---
+author:
+    - Miguel Angel Muñoz (@magonzalez)
+httpapi : fortios
+short_description: HttpApi Plugin for Fortinet FortiOS Appliance or VM
+description:
+  - This HttpApi plugin provides methods to connect to Fortinet FortiOS Appliance or VM via REST API
+version_added: "2.9"
+"""
+
+from ansible.plugins.httpapi import HttpApiBase
+from ansible.module_utils.basic import to_text
+import urllib
+import json
+import re
+
+
+class HttpApi(HttpApiBase):
+    def __init__(self, connection):
+        super(HttpApi, self).__init__(connection)
+
+        self._ccsrftoken = ''
+
+    def set_become(self, become_context):
+        """
+        Elevation is not required on Fortinet devices - Skipped
+        :param become_context: Unused input.
+        :return: None
+        """
+        return None
+
+    def login(self, username, password):
+        """Call a defined login endpoint to receive an authentication token."""
+
+        data = "username=" + urllib.parse.quote(username) + "&secretkey=" + urllib.parse.quote(password) + "&ajax=1"
+        dummy, result_data = self.send_request(url='/logincheck', data=data, method='POST')
+        if result_data[0] != '1':
+            raise Exception('Wrong credentials. Please check')
+
+    def logout(self):
+        """ Call to implement session logout."""
+
+        self.send_request(url='/logout', method="POST")
+
+    def update_auth(self, response, response_text):
+        """
+        Get cookies and obtain value for csrftoken that will be used on next requests
+        :param response: Response given by the server.
+        :param response_text Unused_input.
+        :return: Dictionary containing headers
+        """
+
+        headers = {}
+
+        for attr, val in response.getheaders():
+            if attr == 'Set-Cookie' and 'APSCOOKIE_' in val:
+                headers['Cookie'] = val
+
+            elif attr == 'Set-Cookie' and 'ccsrftoken=' in val:
+                csrftoken_search = re.search('\"(.*)\"', val)
+                if csrftoken_search:
+                    self._ccsrftoken = csrftoken_search.group(1)
+
+        headers['x-csrftoken'] = self._ccsrftoken
+
+        return headers
+
+    def handle_httperror(self, exc):
+        """
+        Not required on Fortinet devices - Skipped
+        :param exc: Unused input.
+        :return: exc
+        """
+        return exc
+
+    def send_request(self, **message_kwargs):
+        """
+        Responsible for actual sending of data to the connection httpapi base plugin.
+        :param message_kwargs: A formatted dictionary containing request info: url, data, method
+
+        :return: Status code and response data.
+        """
+        url = message_kwargs.get('url', '/')
+        data = message_kwargs.get('data', '')
+        method = message_kwargs.get('method', 'GET')
+
+        try:
+            response, response_data = self.connection.send(url, data, method=method)
+
+            return response.status, to_text(response_data.getvalue())
+        except Exception as err:
+            raise Exception(err)