diff --git a/includes/abstract-integration.php b/includes/abstract-integration.php
index 069db6ef441653442e1a383bc40eed3c3d5eb41f..bc576462b1d23996e037ca2d40f71286a1bc1dd2 100644
--- a/includes/abstract-integration.php
+++ b/includes/abstract-integration.php
@@ -8,29 +8,108 @@ use Exception;
 
 abstract class Integration extends Singleton
 {
+    /**
+     * Retrive the current form.
+     *
+     * @return array $form_data Form data array representation.
+     */
+    abstract public function get_form();
+
+    /**
+     * Retrive form by ID.
+     *
+     * @since 3.0.0
+     *
+     * @return array $form_data Form data array representation.
+     */
+    abstract public function get_form_by_id($form_id);
+
+    /**
+     * Retrive available integration forms.
+     *
+     * @since 3.0.0
+     *
+     * @return array $forms Collection of form data array representations.
+     */
+    abstract public function get_forms();
+
+    /**
+     * Retrive the current form submission.
+     *
+     * @since 3.0.0
+     *
+     * @return array $submission Submission data array representation.
+     */
+    abstract public function get_submission();
+
+    /**
+     * Retrive the current submission uploaded files.
+     *
+     * @since 3.0.0
+     *
+     * @return array $files Collection of file array representations.
+     */
+    abstract public function get_uploads();
+
+    /**
+     * Serialize the current form submission data.
+     *
+     * @since 1.0.0
+     *
+     * @param any $submission Pair plugin submission handle.
+     * @param array $form_data Source form data.
+     * @return array $submission_data Submission data.
+     */
     abstract public function serialize_submission($submission, $form);
+
+    /**
+     * Serialize the current form data.
+     *
+     * @since 1.0.0
+     *
+     * @param any $form Pair plugin form handle.
+     * @return array $form_data Form data.
+     */
     abstract public function serialize_form($form);
-    abstract protected function get_uploads($submission, $form_data);
-    abstract protected function init();
 
-    private $submission = [];
-    private $uploads = [];
+    /**
+     * Get uploads from pair submission handle.
+     *
+     * @since 1.0.0
+     *
+     * @param any $submission Pair plugin submission handle.
+     * @param array $form_data Current form data.
+     * @return array $uploads Collection of file array representations.
+     */
+    abstract protected function submission_uploads($submission, $form_data);
+
+    /**
+     * Integration initializer to be fired on wp init.
+     *
+     * @since 0.0.1
+     */
+    abstract protected function init();
 
+    /**
+     * Bind integration initializer to wp init hook.
+     *
+     * @since 0.0.1
+     */
     protected function __construct()
     {
         add_action('init', function () {
             $this->init();
         });
-
-        add_filter('wpct_erp_forms_submission', function ($null) {
-            return $this->submission;
-        });
-
-        add_filter('wpct_erp_forms_uploads', function ($null) {
-            return $this->uploads;
-        });
     }
 
+    /**
+     * Submit many requests with Wpct_Http_Client.
+     *
+     * @since 1.0.0
+     *
+     * @param array $requests Array of requests.
+     * @return boolean $success Submit resolution.
+     */
     private function submit($requests)
     {
         $success = true;
@@ -43,14 +122,29 @@ abstract class Integration extends Singleton
             if (empty($attachments)) {
                 $response = Wpct_Http_Client::post($endpoint, $payload);
             } else {
-                $response = Wpct_Http_Client::post_multipart($endpoint, $payload, $attachments);
+                $response = Wpct_Http_Client::post_multipart(
+                    $endpoint,
+                    $payload,
+                    $attachments
+                );
             }
 
-            $success = $success && !is_wp_error($response) && apply_filters('_wpct_erp_forms_validate_rpc_response', true, $response);
+            $success =
+                $success &&
+                !is_wp_error($response) &&
+                apply_filters(
+                    '_wpct_erp_forms_validate_rpc_response',
+                    true,
+                    $response
+                );
         }
 
         if (!$success) {
-            $email = Settings::get_setting('wpct-erp-forms', 'general', 'notification_receiver');
+            $email = Settings::get_setting(
+                'wpct-erp-forms',
+                'general',
+                'notification_receiver'
+            );
             if (empty($email)) {
                 return;
             }
@@ -60,22 +154,36 @@ abstract class Integration extends Singleton
             $body = "Form ID: {$form_data['id']}\n";
             $body .= "Form title: {$form_data['title']}\n";
             $body .= 'Submission: ' . print_r($payload, true) . "\n";
-            $body .= 'Error: ' . print_r($response->get_error_data(), true) . "\n";
+            $body .=
+                'Error: ' . print_r($response->get_error_data(), true) . "\n";
             $success = wp_mail($to, $subject, $body);
             if (!$success) {
-                throw new Exception('Error while submitting form ' . $form_data['id']);
+                throw new Exception(
+                    'Error while submitting form ' . $form_data['id']
+                );
             }
         }
 
         return $success;
     }
 
+    /**
+     * Submit RPC form hooks.
+     *
+     * @since 2.0.0
+     *
+     * @param array $models Array of target models.
+     * @param array $payload Submission data.
+     * @param array $attachments Collection of attachment files.
+     * @param array $form_data Source form data.
+     * @return boolean $result Submit result.
+     */
     private function submit_rpc($models, $payload, $attachments, $form_data)
     {
         $setting = Settings::get_setting('wpct-erp-forms', 'rpc-api');
 
         try {
-            [ $session_id, $user_id ] = $this->rpc_login($setting['endpoint']);
+            [$session_id, $user_id] = $this->rpc_login($setting['endpoint']);
         } catch (Exception) {
             return false;
         }
@@ -86,25 +194,31 @@ abstract class Integration extends Singleton
             $attachments,
             $form_data,
             $session_id,
-            $user_id,
+            $user_id
         ) {
+            $pipes = [];
+            foreach ($setting['hooks'] as $hook) {
+                if (
+                    $hook['form_id'] == $form_data['id'] &&
+                    $hook['endpoint'] === $endpoint
+                ) {
+                    $pipes = $hook['pipes'];
+                    break;
+                }
+            }
+
             $payload = apply_filters(
                 'wpct_erp_forms_rpc_payload',
-                $this->rpc_payload(
-                    $session_id,
-                    'object',
-                    'execute',
-                    [
-                        $setting['database'],
-                        $user_id,
-                        $setting['password'],
-                        $model,
-                        'create',
-                        $payload
-                    ],
-                ),
+                $this->rpc_payload($session_id, 'object', 'execute', [
+                    $setting['database'],
+                    $user_id,
+                    $setting['password'],
+                    $model,
+                    'create',
+                    $this->apply_pipes($payload, $pipes),
+                ]),
                 $attachments,
-                $form_data,
+                $form_data
             );
 
             return [
@@ -115,21 +229,57 @@ abstract class Integration extends Singleton
             ];
         }, $models);
 
-        $validation = fn ($result, $res) => $this->rpc_response_validation($res);
+        $validation = fn($result, $res) => $this->rpc_response_validation($res);
         add_filter('_wpct_erp_forms_validate_rpc_response', $validation, 2, 10);
 
         $result = $this->submit($requests);
 
-        remove_filter('_wpct_erp_forms_validate_rpc_response', $validation, 2, 10);
+        remove_filter(
+            '_wpct_erp_forms_validate_rpc_response',
+            $validation,
+            2,
+            10
+        );
         return $result;
     }
 
+    /**
+     * Submit REST from hooks.
+     *
+     * @since 2.0.0
+     *
+     * @param array $endpoints Array of target endpoints.
+     * @param array $payload Submission data.
+     * @param array $attachments Collection of attachment files.
+     * @param array $form_data Source form data.
+     * @return boolean $result Submit result.
+     */
     private function submit_rest($endpoints, $payload, $attachments, $form_data)
     {
-        $requests = array_map(function ($endpoint) use ($payload, $attachments, $form_data) {
+        ['form_hooks' => $hooks] = Settings::get_setting(
+            'wpct-erp-forms',
+            'rest-api'
+        );
+        $requests = array_map(function ($endpoint) use (
+            $payload,
+            $attachments,
+            $form_data,
+            $hooks
+        ) {
+            $pipes = [];
+            foreach ($hooks as $hook) {
+                if (
+                    $hook['form_id'] == $form_data['id'] &&
+                    $hook['endpoint'] === $endpoint
+                ) {
+                    $pipes = $hook['pipes'];
+                    break;
+                }
+            }
+
             return [
                 'endpoint' => $endpoint,
-                'payload' => $payload,
+                'payload' => $this->apply_pipes($payload, $pipes),
                 'attachments' => $attachments,
                 'form_data' => $form_data,
             ];
@@ -138,6 +288,14 @@ abstract class Integration extends Singleton
         return $this->submit($requests);
     }
 
+    /**
+     * Form hooks submission subroutine.
+     *
+     * @since 1.0.0
+     *
+     * @param any $submission Pair plugin submission handle.
+     * @param any $form Pair plugin form handle.
+     */
     public function do_submission($submission, $form)
     {
         $form_data = $this->serialize_form($form);
@@ -145,86 +303,209 @@ abstract class Integration extends Singleton
             return;
         }
 
-        $uploads = $this->get_uploads($submission, $form_data);
-        $this->uploads = array_reduce(array_keys($uploads), function ($carry, $name) use ($uploads) {
-            if ($uploads[$name]['is_multi']) {
-                for ($i = 1; $i <= count($uploads[$name]['path']); $i++) {
-                    $carry[$name . '_' . $i] = $uploads[$name]['path'][$i - 1];
+        $uploads = $this->submission_uploads($submission, $form_data);
+        $uploads = array_reduce(
+            array_keys($uploads),
+            function ($carry, $name) use ($uploads) {
+                if ($uploads[$name]['is_multi']) {
+                    for ($i = 1; $i <= count($uploads[$name]['path']); $i++) {
+                        $carry[$name . '_' . $i] =
+                            $uploads[$name]['path'][$i - 1];
+                    }
+                } else {
+                    $carry[$name] = $uploads[$name]['path'];
                 }
-            } else {
-                $carry[$name] = $uploads[$name]['path'];
-            }
 
-            return $carry;
-        }, []);
+                return $carry;
+            },
+            []
+        );
 
-        $attachments = apply_filters('wpct_erp_forms_attachments', $uploads, $form_data);
+        $attachments = apply_filters(
+            'wpct_erp_forms_attachments',
+            $uploads,
+            $form_data
+        );
 
-        $this->submission = $this->serialize_submission($submission, $form_data);
+        $submission = $this->serialize_submission($submission, $form_data);
         $this->cleanup_empties($submission);
-        $payload = apply_filters('wpct_erp_forms_payload', $this->submission, $attachments, $form_data);
+        $payload = apply_filters(
+            'wpct_erp_forms_payload',
+            $submission,
+            $attachments,
+            $form_data
+        );
 
-        $endpoints = apply_filters('wpct_erp_forms_endpoints', $this->get_form_endpoints($form_data['id']), $payload, $attachments, $form_data);
-        $models = apply_filters('wpct_erp_forms_models', $this->get_form_models($form_data['id']), $payload, $attachments, $form_data);
+        $endpoints = apply_filters(
+            'wpct_erp_forms_endpoints',
+            $this->get_form_endpoints($form_data['id']),
+            $payload,
+            $attachments,
+            $form_data
+        );
+        $models = apply_filters(
+            'wpct_erp_forms_models',
+            $this->get_form_models($form_data['id']),
+            $payload,
+            $attachments,
+            $form_data
+        );
 
-        do_action('wpct_erp_forms_before_submission', $payload, $attachments, $form_data);
+        do_action(
+            'wpct_erp_forms_before_submission',
+            $payload,
+            $attachments,
+            $form_data
+        );
 
-        $success = $this->submit_rest($endpoints, $payload, $attachments, $form_data);
-        $success = $success && $this->submit_rpc($models, $payload, $attachments, $form_data);
+        $success = $this->submit_rest(
+            $endpoints,
+            $payload,
+            $attachments,
+            $form_data
+        );
+        $success =
+            $success &&
+            $this->submit_rpc($models, $payload, $attachments, $form_data);
 
         if ($success) {
-            do_action('wpct_erp_forms_after_submission', $payload, $attachments, $form_data);
+            do_action(
+                'wpct_erp_forms_after_submission',
+                $payload,
+                $attachments,
+                $form_data
+            );
         } else {
-            do_action('wpct_erp_forms_on_failure', $payload, $attachments, $form_data);
+            do_action(
+                'wpct_erp_forms_on_failure',
+                $payload,
+                $attachments,
+                $form_data
+            );
+        }
+    }
+
+    /**
+     * Apply cast pipes to the submission data.
+     *
+     * @since 3.0.0
+     *
+     * @param array $payload Submission data.
+     * @param array $form_data Form data.
+     */
+    private function apply_pipes($payload, $form_data)
+    {
+        ['form_hooks' => $rest_hooks] = Settings::get_setting(
+            'wpct-erp-forms',
+            'rest-api'
+        );
+        ['form_hooks' => $rpc_hooks] = Settings::get_setting(
+            'wpct-erp-forms',
+            'rpc-api'
+        );
+
+        foreach (array_merge($rest_hooks, $rpc_hooks) as $hook) {
+            if ($hook['form_id'] == $form_data['id']) {
+            }
         }
     }
 
-    private function cleanup_empties(&$submission)
+    /**
+     * Clean up submission empty fields.
+     *
+     * @since 1.0.0
+     *
+     * @param array $submission_data Submission data.
+     * @return array $submission_data Submission data without empty fields.
+     */
+    private function cleanup_empties(&$submission_data)
     {
-        foreach ($submission as $key => $val) {
+        foreach ($submission_data as $key => $val) {
             if (empty($val)) {
-                unset($submission[$key]);
+                unset($submission_data[$key]);
             }
         }
 
-        return $submission;
+        return $submission_data;
     }
 
+    /**
+     * Get form RPC bounded models.
+     *
+     * @since 2.0.0
+     *
+     * @param int $form_id Form ID.
+     * @return array $models Array of model names.
+     */
     private function get_form_models($form_id)
     {
-        $rpc_forms = Settings::get_setting('wpct-erp-forms', 'rpc-api', 'forms');
-        return array_unique(array_map(function ($form) {
-            return $form['model'];
-        }, array_filter($rpc_forms, function ($form) use ($form_id) {
-            return (string) $form['form_id'] === (string) $form_id && !empty($form['model']);
-        })));
+        $rpc_forms = Settings::get_setting(
+            'wpct-erp-forms',
+            'rpc-api',
+            'forms'
+        );
+        return array_unique(
+            array_map(
+                function ($form) {
+                    return $form['model'];
+                },
+                array_filter($rpc_forms, function ($form) use ($form_id) {
+                    return (string) $form['form_id'] === (string) $form_id &&
+                        !empty($form['model']);
+                })
+            )
+        );
     }
 
+    /**
+     * Get form REST bounded endpoints.
+     *
+     * @since 2.0.0
+     *
+     * @param int $form_id Form ID.
+     * @return array $endpoints Array of endpoints.
+     */
     private function get_form_endpoints($form_id)
     {
-        $rest_forms = Settings::get_setting('wpct-erp-forms', 'rest-api', 'forms');
-        return array_unique(array_map(function ($form) {
-            return $form['endpoint'];
-        }, array_filter($rest_forms, function ($form) use ($form_id) {
-            return (string) $form['form_id'] === (string) $form_id && !empty($form['endpoint']);
-        })));
+        $rest_forms = Settings::get_setting(
+            'wpct-erp-forms',
+            'rest-api',
+            'forms'
+        );
+        return array_unique(
+            array_map(
+                function ($form) {
+                    return $form['endpoint'];
+                },
+                array_filter($rest_forms, function ($form) use ($form_id) {
+                    return (string) $form['form_id'] === (string) $form_id &&
+                        !empty($form['endpoint']);
+                })
+            )
+        );
     }
 
+    /**
+     * JSON RPC login request.
+     *
+     * @since 2.0.0
+     *
+     * @param string $endpoint Target endpoint.
+     * @return array $credentials Tuple with $session_id and $user_id.
+     */
     private function rpc_login($endpoint)
     {
         $session_id = time();
         $setting = Settings::get_setting('wpct-erp-forms', 'rpc-api');
 
-        $payload = apply_filters('wpct_erp_forms_rpc_login', $this->rpc_payload(
-            $session_id,
-            'common',
-            'login',
-            [
+        $payload = apply_filters(
+            'wpct_erp_forms_rpc_login',
+            $this->rpc_payload($session_id, 'common', 'login', [
                 $setting['database'],
                 $setting['user'],
                 $setting['password'],
-            ],
-        ));
+            ])
+        );
 
         $res = Wpct_Http_Client::post($endpoint, $payload);
 
@@ -240,6 +521,17 @@ abstract class Integration extends Singleton
         return [$session_id, $user_id];
     }
 
+    /**
+     * RPC payload decorator.
+     *
+     * @since 2.0.0
+     *
+     * @param int $session_id RPC session ID.
+     * @param string $service RPC service name.
+     * @param string $method RPC method name.
+     * @param array $args RPC request arguments.
+     * @return array $payload RPC conformant payload.
+     */
     private function rpc_payload($session_id, $service, $method, $args)
     {
         return [
@@ -254,6 +546,15 @@ abstract class Integration extends Singleton
         ];
     }
 
+    /**
+     * RPC does not work on HTTP standard. This method validate RPC responses
+     * on the application layer.
+     *
+     * @since 2.0.0
+     *
+     * @param array $res RPC response.
+     * @return boolean $result RPC response result.
+     */
     private function rpc_response_validation($res)
     {
         $payload = (array) json_decode($res['body'], true);
diff --git a/includes/class-rest-controller.php b/includes/class-rest-controller.php
index 962733399288183f189a27ff6878413ebb0d22d6..aeebade98da8e4744ba51d841dd95d040e9edeae 100644
--- a/includes/class-rest-controller.php
+++ b/includes/class-rest-controller.php
@@ -7,11 +7,48 @@ use WP_REST_Server;
 
 class REST_Controller
 {
+    /**
+     * @var string $namespace Handle wp rest api plugin namespace.
+     *
+     * @since 3.0.0
+     */
     private $namespace = 'wpct';
+
+    /**
+     * @var int $version Handle the API version.
+     *
+     * @since 3.0.0
+     */
     private $version = 1;
 
+    /**
+     * @var array $settings Handle the plugin settings names list.
+     *
+     * @since 3.0.0
+     */
     private static $settings = ['general', 'rest-api', 'rpc-api'];
 
+    /**
+     * Setup a new rest api controller.
+     *
+     * @since 3.0.0
+     *
+     * @return object $controller Instance of REST_Controller.
+     */
+    public static function setup()
+    {
+        return new REST_Controller();
+    }
+
+    /**
+     * Internal WP_Error proxy.
+     *
+     * @since 3.0.0
+     *
+     * @param string $code
+     * @param string $message
+     * @param int $status
+     */
     private static function error($code, $message, $status)
     {
         return new WP_Error($code, __($message, 'wpct-erp-forms'), [
@@ -19,6 +56,11 @@ class REST_Controller
         ]);
     }
 
+    /**
+     * Binds class initializer to the rest_api_init hook
+     *
+     * @since 3.0.0
+     */
     public function __construct()
     {
         add_action('rest_api_init', function () {
@@ -26,6 +68,11 @@ class REST_Controller
         });
     }
 
+    /**
+     * REST_Controller initializer.
+     *
+     * @since 3.0.0
+     */
     private function init()
     {
         register_rest_route(
@@ -42,20 +89,6 @@ class REST_Controller
             ]
         );
 
-        register_rest_route(
-            "{$this->namespace}/v{$this->version}",
-            '/erp-forms/form/(?P<id>[\d]+)',
-            [
-                'methods' => WP_REST_Server::READABLE,
-                'callback' => function ($req) {
-                    return $this->form_fields($req);
-                },
-                'permission_callback' => function () {
-                    return $this->permission_callback();
-                },
-            ]
-        );
-
         register_rest_route(
             "{$this->namespace}/v{$this->version}",
             '/erp-forms/settings/',
@@ -82,37 +115,25 @@ class REST_Controller
         );
     }
 
+    /**
+     * GET requests forms endpoint callback.
+     *
+     * @since 3.0.0
+     *
+     * @return array $forms Collection of array form representations.
+     */
     private function forms()
     {
-        $forms = Settings::get_forms();
-        $response = [];
-        foreach ($forms as $form) {
-            $response[] = $form;
-        }
-
-        return $response;
-    }
-
-    private function form_fields($req)
-    {
-        $target = null;
-        $form_id = $req->get_url_params()['id'];
-        $forms = Settings::get_forms();
-        foreach ($forms as $form) {
-            if ($form->id === $form_id) {
-                $target = $form;
-                break;
-            }
-        }
-
-        if (!$target) {
-            throw new Exception('Unkown form');
-        }
-
-        $fields = apply_filters('wpct_erp_forms_form_fields', [], $form_id);
-        return $fields;
+        return apply_filters('wpct_erp_forms_forms', []);
     }
 
+    /**
+     * GET requests settings endpoint callback.
+     *
+     * @since 3.0.0
+     *
+     * @return array $settings Associative array with settings data.
+     */
     private function get_settings()
     {
         $settings = [];
@@ -125,6 +146,13 @@ class REST_Controller
         return $settings;
     }
 
+    /**
+     * POST requests settings endpoint callback. Store settings on the options table.
+     *
+     * @since 3.0.0
+     *
+     * @return array $response New settings state.
+     */
     private function set_settings()
     {
         $data = (array) json_decode(file_get_contents('php://input'), true);
@@ -146,18 +174,21 @@ class REST_Controller
         return $response;
     }
 
+    /**
+     * Check if current user can manage options
+     *
+     * @since 3.0.0
+     *
+     * @return boolean $allowed
+     */
     private function permission_callback()
     {
-        // $nonce = $_REQUEST['_wpctnonce'];
-        if (!current_user_can('manage_options')) {
-            // if (!wp_verify_nonce($nonce, 'wpct-erp-forms')) {
-            return self::error(
+        return current_user_can('manage_options')
+            ? true
+            : self::error(
                 'rest_unauthorized',
                 'You can\'t manage wp options',
                 403
             );
-        }
-
-        return true;
     }
 }
diff --git a/includes/class-settings.php b/includes/class-settings.php
index 083af89db3b2ec0721315f5ea4e8fc2323358043..148d09ba3c722091f9877da0e8cbc0dce7c12cd5 100644
--- a/includes/class-settings.php
+++ b/includes/class-settings.php
@@ -6,20 +6,13 @@ use WPCT_ABSTRACT\Settings as BaseSettings;
 
 class Settings extends BaseSettings
 {
-    public function __construct($group_name)
-    {
-        parent::__construct($group_name);
-
-        add_action(
-            'load-settings_page_wpct-erp-forms',
-            function () {
-                echo '<style>.wpct-erp-forms_general__backends table tr { display: flex; flex-direction: column; }</style>';
-            },
-            10,
-            0
-        );
-    }
-
+    /**
+     * Return registered backends.
+     *
+     * @since 3.0.0
+     *
+     * @return array $backends Collection of backend array representations.
+     */
     public static function get_backends()
     {
         $setting = Settings::get_setting('wpct-erp-forms', 'general');
@@ -28,6 +21,13 @@ class Settings extends BaseSettings
         }, $setting['backends']);
     }
 
+    /**
+     * Get form instances from database.
+     *
+     * @since 2.0.0
+     *
+     * @return array $forms Database record objects from form posts.
+     */
     public static function get_forms()
     {
         global $wpdb;
@@ -54,6 +54,11 @@ class Settings extends BaseSettings
         }
     }
 
+    /**
+     * Register plugin settings.
+     *
+     * @since 2.0.0
+     */
     public function register()
     {
         $host = parse_url(get_bloginfo('url'))['host'];
@@ -92,7 +97,7 @@ class Settings extends BaseSettings
                         'base_url' => 'https://erp.' . $host,
                         'headers' => [
                             [
-                                'name' => 'Auhtorization',
+                                'name' => 'Authorization',
                                 'value' => 'Bearer <erp-backend-token>',
                             ],
                         ],
@@ -104,15 +109,15 @@ class Settings extends BaseSettings
         $this->register_setting(
             'rest-api',
             [
-                'forms' => [
+                'form_hooks' => [
                     'type' => 'array',
                     'items' => [
                         'type' => 'object',
                         'properties' => [
+                            'name' => ['type' => 'string'],
                             'backend' => ['type' => 'string'],
                             'form_id' => ['type' => 'string'],
                             'endpoint' => ['type' => 'string'],
-                            'ref' => ['type' => 'string'],
                             'pipes' => [
                                 'type' => 'array',
                                 'items' => [
@@ -120,6 +125,16 @@ class Settings extends BaseSettings
                                     'properties' => [
                                         'from' => ['type' => 'string'],
                                         'to' => ['type' => 'string'],
+                                        'cast' => [
+                                            'type' => 'string',
+                                            'enum' => [
+                                                'boolean',
+                                                'string',
+                                                'integer',
+                                                'float',
+                                                'json',
+                                            ],
+                                        ],
                                     ],
                                 ],
                             ],
@@ -128,15 +143,7 @@ class Settings extends BaseSettings
                 ],
             ],
             [
-                'forms' => [
-                    [
-                        'backend' => 'ERP',
-                        'form_id' => null,
-                        'endpoint' => '/api/crm-lead',
-                        'ref' => null,
-                        'pipes' => [],
-                    ],
-                ],
+                'form_hooks' => [],
             ]
         );
 
@@ -155,15 +162,15 @@ class Settings extends BaseSettings
                 'database' => [
                     'type' => 'string',
                 ],
-                'forms' => [
+                'form_hooks' => [
                     'type' => 'array',
                     'items' => [
                         'type' => 'object',
                         'properties' => [
+                            'name' => ['type' => 'string'],
                             'backend' => ['type' => 'string'],
                             'form_id' => ['type' => 'string'],
                             'model' => ['type' => 'string'],
-                            'ref' => ['type' => 'string'],
                             'pipes' => [
                                 'type' => 'array',
                                 'items' => [
@@ -171,6 +178,16 @@ class Settings extends BaseSettings
                                     'properties' => [
                                         'from' => ['type' => 'string'],
                                         'to' => ['type' => 'string'],
+                                        'cast' => [
+                                            'type' => 'string',
+                                            'enum' => [
+                                                'boolean',
+                                                'string',
+                                                'integer',
+                                                'float',
+                                                'json',
+                                            ],
+                                        ],
                                     ],
                                 ],
                             ],
@@ -183,67 +200,8 @@ class Settings extends BaseSettings
                 'user' => 'admin',
                 'password' => 'admin',
                 'database' => 'erp',
-                'forms' => [
-                    [
-                        'backend' => 'ERP',
-                        'form_id' => 0,
-                        'model' => 'crm.lead',
-                        'ref' => null,
-                        'pipes' => [],
-                    ],
-                ],
+                'form_hooks' => [],
             ]
         );
     }
-
-    protected function input_render($setting, $field, $value, $is_root = false)
-    {
-        if (preg_match('/^forms.*form_id$/', $field)) {
-            return $this->render_forms_dropdown($setting, $field, $value);
-        } elseif (preg_match('/^forms.*backend$/', $field)) {
-            return $this->render_backends_dropdown($setting, $field, $value);
-        } elseif (preg_match('/password$/', $field)) {
-            return $this->password_input_render($setting, $field, $value);
-        }
-
-        return parent::input_render($setting, $field, $value);
-    }
-
-    private function render_backends_dropdown($setting, $field, $value)
-    {
-        $setting_name = $this->setting_name($setting);
-        $backends = self::get_backends();
-        $options = array_merge(
-            ['<option value=""></option>'],
-            array_map(function ($backend) use ($value) {
-                $selected = $backend == $value ? 'selected' : '';
-                return "<option value='{$backend}' {$selected}>{$backend}</option>";
-            }, $backends)
-        );
-        return "<select name='{$setting_name}[{$field}]'>" .
-            implode('', $options) .
-            '</select>';
-    }
-
-    private function render_forms_dropdown($setting, $field, $value)
-    {
-        $setting_name = $this->setting_name($setting);
-        $forms = self::get_forms();
-        $options = array_merge(
-            ['<option value=""></option>'],
-            array_map(function ($form) use ($value) {
-                $selected = $form->id == $value ? 'selected' : '';
-                return "<option value='{$form->id}' {$selected}>{$form->title}</option>";
-            }, $forms)
-        );
-        return "<select name='{$setting_name}[{$field}]'>" .
-            implode('', $options) .
-            '</select>';
-    }
-
-    private function password_input_render($setting, $field, $value)
-    {
-        $setting_name = $this->setting_name($setting);
-        return "<input type='password' name='{$setting_name}[{$field}]' value='{$value}' />";
-    }
 }
diff --git a/includes/integrations/gf/class-integration.php b/includes/integrations/gf/class-integration.php
index 0c334dc641fd583a920bebd1720513a5c038ad40..14f4a8c34b9e7f193f1827dfad66f7bc6f245408 100644
--- a/includes/integrations/gf/class-integration.php
+++ b/includes/integrations/gf/class-integration.php
@@ -5,31 +5,142 @@ namespace WPCT_ERP_FORMS\GF;
 use Exception;
 use TypeError;
 use WPCT_ERP_FORMS\Integration as BaseIntegration;
+use GFCommon;
+use GFAPI;
+use GFFormDisplay;
 
 require_once 'attachments.php';
 require_once 'fields-population.php';
 
 class Integration extends BaseIntegration
 {
+    /**
+     * Inherit prent constructor and hooks submissions to gform_after_submission
+     *
+     * @since 0.0.1
+     */
     protected function __construct()
     {
-        add_action('gform_after_submission', function ($entry, $form) {
-            $this->do_submission($entry, $form);
-        }, 10, 2);
+        add_action(
+            'gform_after_submission',
+            function ($entry, $form) {
+                $this->do_submission($entry, $form);
+            },
+            10,
+            2
+        );
 
         parent::__construct();
     }
 
-	protected function init()
-	{
-	}
+    /**
+     * Integration initializer to be fired on wp init.
+     *
+     * @since 0.0.1
+     */
+    protected function init()
+    {
+    }
+
+    /**
+     * Retrive the current form data.
+     *
+     * @return array $form_data Form data.
+     */
+    public function get_form()
+    {
+        $form_id = null;
+        if (!isset($_POST['gform_submit'])) {
+            require_once GFCommon::get_base_path() . '/form_display.php';
+            $form_id = GFFormDisplay::is_submit_form_id_valid();
+        }
+
+        $form = GFAPI::get_submission_form($form_id);
+        if (is_wp_error($form)) {
+            return null;
+        }
 
+        return $this->serialize_form($form);
+    }
+
+    /**
+     * Retrive form data by ID.
+     *
+     * @since 3.0.0
+     *
+     * @param int $form_id Form ID.
+     * @return array $form_data Form data.
+     */
+    public function get_form_by_id($form_id)
+    {
+        $form = GFAPI::get_form($form_id);
+        if (!$form) {
+            return null;
+        }
+
+        return $this->serialize_form($form);
+    }
+
+    /**
+     * Retrive available forms data.
+     *
+     * @since 3.0.0
+     *
+     * @return array $forms Collection of form data array representations.
+     */
+    public function get_forms()
+    {
+        $forms = GFAPI::get_forms();
+        return array_map(
+            function ($form) {
+                return $this->serialize_form($form);
+            },
+            array_filter($forms, function ($form) {
+                return $form['is_active'] && !$form['is_trash'];
+            })
+        );
+    }
+
+    /**
+     * Retrive the current submission data.
+     *
+     * @since 3.0.0
+     *
+     * @return array $submission Submission data.
+     */
+    public function get_submission()
+    {
+        $form = $this->get_form();
+        if (!$form) {
+            return null;
+        }
+
+        $submission = GFAPI::get_submission();
+        $lead_id = gf_apply_filters(
+            ['gform_entry_id_pre_save_lead', $form_id],
+            null,
+            $form
+        );
+    }
+
+    /**
+     * Serialize gf form data.
+     *
+     * @since 1.0.0
+     *
+     * @param array $form GF form data.
+     * @return array $form_data Form data.
+     */
     public function serialize_form($form)
     {
         return [
             'id' => $form['id'],
             'title' => $form['title'],
-            'ref' => apply_filters('wpct_erp_forms_form_ref', null, $form['id']),
+            'hooks' => apply_filters(
+                'wpct_erp_forms_form_hooks',
+                null,
+                $form['id']
+            ),
             'description' => $form['description'],
             'fields' => array_map(function ($field) {
                 return $this->serialize_field($field);
@@ -38,7 +149,16 @@ class Integration extends BaseIntegration
         return $form;
     }
 
-    private function serialize_field($field)
+    /**
+     * Serialize GF form data field.
+     *
+     * @since 1.0.0
+     *
+     * @param object GFField instance.
+     * @param array From data.
+     * @return array $field_data Field data.
+     */
+    private function serialize_field($field, $form_data)
     {
         switch ($field->type) {
             case 'fileupload':
@@ -58,7 +178,11 @@ class Integration extends BaseIntegration
         $inputs = $field->get_entry_inputs();
         if (is_array($inputs)) {
             $inputs = array_map(function ($input) {
-                return ['name' => $input['name'], 'label' => $input['label'], 'id' => $input['id']];
+                return [
+                    'name' => $input['name'],
+                    'label' => $input['label'],
+                    'id' => $input['id'],
+                ];
             }, $inputs);
         } else {
             $inputs = [];
@@ -79,23 +203,33 @@ class Integration extends BaseIntegration
             'required' => $field->isRequired,
             'options' => $options,
             'inputs' => $inputs,
-            'conditional' => is_array($field->conditionalLogic) && $field->conditionalLogic['enabled'],
+            'conditional' =>
+                is_array($field->conditionalLogic) &&
+                $field->conditionalLogic['enabled'],
         ];
     }
 
-
+    /**
+     * Serialize current form submission data.
+     *
+     * @since 1.0.0
+     *
+     * @param array $submission GF form lead.
+     * @param array @form Form data.
+     * @return array $submission_data Submission data.
+     */
     public function serialize_submission($submission, $form_data)
     {
         $data = [
-            'submission_id' => $submission['id']
+            'submission_id' => $submission['id'],
         ];
 
         foreach ($form_data['fields'] as $field) {
             if (
-                $field['type'] === 'section'
-                    || $field['type'] === 'file'
-                    || $field['type'] === 'files'
-                    || $field['type'] === 'html'
+                $field['type'] === 'section' ||
+                $field['type'] === 'file' ||
+                $field['type'] === 'files' ||
+                $field['type'] === 'html'
             ) {
                 continue;
             }
@@ -114,7 +248,10 @@ class Integration extends BaseIntegration
                         if (empty($names[$i])) {
                             continue;
                         }
-                        $data[$names[$i]] = rgar($submission, (string) $inputs[$i]['id']);
+                        $data[$names[$i]] = rgar(
+                            $submission,
+                            (string) $inputs[$i]['id']
+                        );
                     }
                 } else {
                     // Plain composed
@@ -122,7 +259,11 @@ class Integration extends BaseIntegration
                     foreach ($inputs as $input) {
                         $value = rgar($submission, (string) $input['id']);
                         if ($input_name && $value) {
-                            $value = $this->format_value($value, $field, $input);
+                            $value = $this->format_value(
+                                $value,
+                                $field,
+                                $input
+                            );
                             if ($value !== null) {
                                 $values[] = $value;
                             }
@@ -139,7 +280,10 @@ class Integration extends BaseIntegration
                     } else {
                         $raw_value = rgar($submission, (string) $field['id']);
                     }
-                    $data[$input_name] = $this->format_value($raw_value, $field);
+                    $data[$input_name] = $this->format_value(
+                        $raw_value,
+                        $field
+                    );
                 }
             }
         }
@@ -147,6 +291,16 @@ class Integration extends BaseIntegration
         return $data;
     }
 
+    /**
+     * Format field values with noop fallback.
+     *
+     * @since 1.0.0
+     *
+     * @param any $value Field value.
+     * @param object $field GFField instance.
+     * @param array $input GFField input data.
+     * @return any $value Formatted value.
+     */
     private function format_value($value, $field, $input = null)
     {
         try {
@@ -165,35 +319,51 @@ class Integration extends BaseIntegration
         return $value;
     }
 
-    protected function get_uploads($submission, $form_data)
+    /**
+     * Get current submission uploaded files.
+     *
+     * @since 1.0.0
+     *
+     * @param array $submission GF lead data.
+     * @param array $form_data Form data.
+     * @return array $uploads Uploaded files data.
+     */
+    protected function submission_uploads($submission, $form_data)
     {
         $private_upload = wpct_erp_forms_private_upload($form_data['id']);
 
-        return array_reduce(array_filter($form_data['fields'], function ($field) {
-            return $field['type'] === 'file' || $field['type'] === 'files';
-        }), function ($carry, $field) use ($submission, $private_upload) {
-            $paths = rgar($submission, (string) $field['id']);
-            if (empty($paths)) {
-                return $carry;
-            }
-
-            $paths = $field['type'] === 'files' ? json_decode($paths) : [$paths];
-            $paths = array_map(function ($path) use ($private_upload) {
-                if ($private_upload) {
-                    $url = parse_url($path);
-                    parse_str($url['query'], $query);
-                    $path = wpct_erp_forms_attachment_fullpath($query['erp-forms-attachment']);
+        return array_reduce(
+            array_filter($form_data['fields'], function ($field) {
+                return $field['type'] === 'file' || $field['type'] === 'files';
+            }),
+            function ($carry, $field) use ($submission, $private_upload) {
+                $paths = rgar($submission, (string) $field['id']);
+                if (empty($paths)) {
+                    return $carry;
                 }
 
-                return $path;
-            }, $paths);
+                $paths =
+                    $field['type'] === 'files' ? json_decode($paths) : [$paths];
+                $paths = array_map(function ($path) use ($private_upload) {
+                    if ($private_upload) {
+                        $url = parse_url($path);
+                        parse_str($url['query'], $query);
+                        $path = wpct_erp_forms_attachment_fullpath(
+                            $query['erp-forms-attachment']
+                        );
+                    }
+
+                    return $path;
+                }, $paths);
 
-            $carry[$field['name']] = [
-                'path' => $field['type'] === 'files' ? $paths : $paths[0],
-                'is_multi' => $field['type'] === 'files'
-            ];
+                $carry[$field['name']] = [
+                    'path' => $field['type'] === 'files' ? $paths : $paths[0],
+                    'is_multi' => $field['type'] === 'files',
+                ];
 
-            return $carry;
-        }, []);
+                return $carry;
+            },
+            []
+        );
     }
 }
diff --git a/includes/integrations/wpcf7/class-integration.php b/includes/integrations/wpcf7/class-integration.php
index ab43d944505c4e5bdc492bfc1e545c2d340ccc32..6a19dfe262b7a4057bb50260276967fc4c358346 100644
--- a/includes/integrations/wpcf7/class-integration.php
+++ b/includes/integrations/wpcf7/class-integration.php
@@ -3,22 +3,155 @@
 namespace WPCT_ERP_FORMS\WPCF7;
 
 use WPCT_ERP_FORMS\Integration as BaseIntegration;
+use WPCF7_ContactForm;
+use WPCF7_Submission;
 
 class Integration extends BaseIntegration
 {
+    /**
+     * Inherit parent constructor and hooks submissions to wpcf7_before_send_mail
+     *
+     * @since 0.0.1
+     */
     protected function __construct()
     {
         parent::__construct();
 
-        add_filter('wpcf7_before_send_mail', function ($form, &$abort, $submission) {
-            $this->do_submission($submission, $form);
-        }, 10, 3);
+        add_filter(
+            'wpcf7_before_send_mail',
+            function ($form, &$abort, $submission) {
+                $this->do_submission($submission, $form);
+            },
+            10,
+            3
+        );
     }
 
+    /**
+     * Integration initializer to be fired on wp init.
+     *
+     * @since 0.0.1
+     */
     protected function init()
     {
     }
 
+    /**
+     * Retrive the current WPCF7_ContactForm data.
+     *
+     * @return array $form_data Form data array representation.
+     */
+    public function get_form()
+    {
+        $form = WPCF7_ContactForm::get_current();
+        if (!$form) {
+            return null;
+        }
+
+        return $this->serialize_form($form);
+    }
+
+    /**
+     * Retrive form data by ID.
+     *
+     * @since 3.0.0
+     *
+     * @param int $form_id Form ID.
+     * @return array $form_data Form data.
+     */
+    public function get_form_by_id($form_id)
+    {
+        $form = WPCF7_ContactForm::get_instance($form_id);
+        if (!$form) {
+            return null;
+        }
+
+        return $this->serialize_form($form);
+    }
+
+    /**
+     * Retrive available integration forms data.
+     *
+     * @since 3.0.0
+     *
+     * @return array $forms Collection of form data.
+     */
+    public function get_forms()
+    {
+        $forms = WPCF7_ContactForm::find(['post_status', 'publish']);
+        return array_map(function ($form) {
+            return $this->serialize_form($form);
+        }, $forms);
+    }
+
+    /**
+     * Retrive the current WPCF7_Submission data.
+     *
+     * @since 3.0.0
+     *
+     * @return array $submission Submission data.
+     */
+    public function get_submission()
+    {
+        $submission = WPCF7_Submission::get_instance();
+        if (!$submission) {
+            return null;
+        }
+
+        return $this->serialize_submission($submission, $this->get_form());
+    }
+
+    /**
+     * Retrive the current WPCF7_Submission uploaded files.
+     *
+     * @since 3.0.0
+     *
+     * @return array $files Uploaded files data.
+     */
+    public function get_uploads()
+    {
+        $submission = WPCF7_Submission::get_instance();
+        if (!$submission) {
+            return null;
+        }
+
+        return $this->submission_uploads($submission, $this->get_form());
+    }
+
+    /**
+     * Serialize WPCF7_ContactForm data.
+     *
+     * @since 1.0.0
+     *
+     * @param object $form WPCF7_ContactForm instance.
+     * @return array $form_data Form data.
+     */
+    public function serialize_form($form)
+    {
+        $form_id = $form->id();
+        return [
+            'id' => $form_id,
+            'title' => $form->title(),
+            'hooks' => apply_filters(
+                'wpct_erp_forms_form_hooks',
+                null,
+                $form_id
+            ),
+            'fields' => array_map(function ($field) use ($form) {
+                return $this->serialize_field($field, $form);
+            }, $form->scan_form_tags()),
+        ];
+    }
+
+    /**
+     * Serialize WPCF7_FormTag to array.
+     *
+     * @since 1.0.0
+     *
+     * @param object $field WPCF7_FormTag instance.
+     * @param array $form_data Form data.
+     * @return array $field_data Field data.
+     */
     private function serialize_field($field, $form_data)
     {
         $type = $field->basetype;
@@ -44,10 +177,21 @@ class Integration extends BaseIntegration
             'label' => $field->name,
             'required' => $field->is_required(),
             'options' => $options,
-            'conditional' => $field->basetype === 'conditional' || $field->basetype === 'fileconditional',
+            'conditional' =>
+                $field->basetype === 'conditional' ||
+                $field->basetype === 'fileconditional',
         ];
     }
 
+    /**
+     * Serialize the WPCF7_Submission data.
+     *
+     * @since 1.0.0
+     *
+     * @param object $submission WPCF7_Submission instance.
+     * @param array $form Form data.
+     * @return array $submission_data Submission data.
+     */
     public function serialize_submission($submission, $form_data)
     {
         $data = $submission->get_posted_data();
@@ -63,7 +207,10 @@ class Integration extends BaseIntegration
                 }
             } elseif ($field['type'] === 'number') {
                 $data[$key] = (float) $val;
-            } elseif ($field['type'] === 'file' || $field['type'] === 'submit') {
+            } elseif (
+                $field['type'] === 'file' ||
+                $field['type'] === 'submit'
+            ) {
                 unset($data[$key]);
             }
         }
@@ -71,20 +218,16 @@ class Integration extends BaseIntegration
         return $data;
     }
 
-    public function serialize_form($form)
-    {
-		$form_id = $form->id();
-        return [
-            'id' => $form_id,
-            'title' => $form->title(),
-            'ref' => apply_filters('wpct_erp_forms_form_ref', null, $form_id),
-            'fields' => array_map(function ($field) use ($form) {
-                return $this->serialize_field($field, $form);
-            }, $form->scan_form_tags()),
-        ];
-    }
-
-    protected function get_uploads($submission, $form_data)
+    /**
+     * Get WPCF7_Submission uploaded files.
+     *
+     * @since 1.0.0
+     *
+     * @param object $submission WPCF7_Submission instance.
+     * @param array $form_data Form data.
+     * @return array $uploads Uploaded files data.
+     */
+    protected function submission_uploads($submission, $form_data)
     {
         $uploads = [];
         $uploads = $submission->uploaded_files();
@@ -96,7 +239,7 @@ class Integration extends BaseIntegration
                     'is_multi' => $is_multi,
                 ];
             }
-        };
+        }
 
         return $uploads;
     }
diff --git a/src/FormPipes/Table.jsx b/src/FormPipes/Table.jsx
index 49ac9697fd130e0a03024cdd01c33b39c975dc2c..65a20423b1768309e50a40ea7edd4c1de0b88283 100644
--- a/src/FormPipes/Table.jsx
+++ b/src/FormPipes/Table.jsx
@@ -12,8 +12,31 @@ import { useEffect } from "@wordpress/element";
 // vendor
 import useFormFields from "../hooks/useFormFields";
 
+const castOptions = [
+  {
+    value: "string",
+    label: __("String", "wpct-erp-forms"),
+  },
+  {
+    value: "int",
+    label: __("Integer", "wpct-erp-forms"),
+  },
+  {
+    value: "float",
+    label: __("Decimal", "wpct-erp-forms"),
+  },
+  {
+    value: "boolean",
+    label: __("Boolean", "wpct-erp-forms"),
+  },
+  {
+    value: "json",
+    label: __("JSON", "wpct-erp-forms"),
+  },
+];
+
 export default function PipesTable({ formId, pipes, setPipes }) {
-  const { fields, loading } = useFormFields({ formId });
+  const fields = useFormFields({ formId });
   const fromOptions = fields.map((field) => ({
     label: field.label,
     value: field.name,
@@ -29,7 +52,7 @@ export default function PipesTable({ formId, pipes, setPipes }) {
   };
 
   const addPipe = () => {
-    const newPipes = pipes.concat([{ from: "", to: "" }]);
+    const newPipes = pipes.concat([{ from: "", to: "", cast: "string" }]);
     setPipes(newPipes);
   };
 
@@ -42,8 +65,6 @@ export default function PipesTable({ formId, pipes, setPipes }) {
     if (!pipes.length) addPipe();
   }, [pipes]);
 
-  if (loading) return <p>Loading...</p>;
-
   return (
     <div className="components-base-control__label">
       <label
@@ -59,11 +80,11 @@ export default function PipesTable({ formId, pipes, setPipes }) {
       </label>
       <table style={{ width: "100%" }}>
         <tbody>
-          {pipes.map(({ from, to }, i) => (
+          {pipes.map(({ from, to, cast }, i) => (
             <tr key={i}>
               <td>
                 <SelectControl
-                  label={__("From", "wpct-erp-forms")}
+                  placeholder={__("From", "wpct-erp-forms")}
                   value={from}
                   onChange={(value) => setPipe("from", i, value)}
                   options={fromOptions}
@@ -78,6 +99,15 @@ export default function PipesTable({ formId, pipes, setPipes }) {
                   __nextHasNoMarginBottom
                 />
               </td>
+              <td style={{ borderLeft: "1rem solid transparent" }}>
+                <SelectControl
+                  placeholder={__("Cast as", "wpct-erp-forms")}
+                  value={cast || "string"}
+                  onChange={(value) => setPipe("cast", i, value)}
+                  options={castOptions}
+                  __nextHasNoMarginBottom
+                />
+              </td>
               <td style={{ borderLeft: "1rem solid transparent" }}>
                 <Button
                   isDestructive
diff --git a/src/RestApiSettings/Forms/Form.jsx b/src/RestApiSettings/FormHooks/FormHook.jsx
similarity index 78%
rename from src/RestApiSettings/Forms/Form.jsx
rename to src/RestApiSettings/FormHooks/FormHook.jsx
index 49d51bad39d5d2bd34e77c98959afeacc6509031..ba371c83a1c4748f77b79f43800de6cc4af620df 100644
--- a/src/RestApiSettings/Forms/Form.jsx
+++ b/src/RestApiSettings/FormHooks/FormHook.jsx
@@ -7,9 +7,10 @@ import { useState, useRef, useEffect } from "@wordpress/element";
 // source
 import { useForms } from "../../providers/Forms";
 import { useGeneral } from "../../providers/Settings";
+import useHookNames from "../../hooks/useHookNames";
 import FormPipes from "../../FormPipes";
 
-function NewForm({ add }) {
+function NewFormHook({ add }) {
   const [{ backends }] = useGeneral();
   const backendOptions = backends.map(({ name, base_url }) => ({
     label: name,
@@ -21,14 +22,22 @@ function NewForm({ add }) {
     value: id,
   }));
 
+  const hookNames = useHookNames();
+
   const [name, setName] = useState("");
   const [backend, setBackend] = useState("");
   const [endpoint, setEndpoint] = useState("");
   const [formId, setFormId] = useState("");
+  const [nameConflict, setNameConflict] = useState(false);
+
+  const handleSetName = (name) => {
+    setNameConflict(hookNames.has(name));
+    setName(name.trim());
+  };
 
   const onClick = () => add({ name, backend, endpoint, form_id: formId });
 
-  const disabled = !(name && backend && endpoint && formId);
+  const disabled = !(name && backend && endpoint && formId && !nameConflict);
 
   return (
     <div
@@ -45,9 +54,14 @@ function NewForm({ add }) {
         }}
       >
         <TextControl
-          label={__("Bound ID", "wpct-erp-forms")}
+          label={__("Name", "wpct-erp-forms")}
+          help={
+            nameConflict
+              ? __("This name is already in use", "wpct-erp-forms")
+              : ""
+          }
           value={name}
-          onChange={setName}
+          onChange={handleSetName}
           __nextHasNoMarginBottom
         />
         <SelectControl
@@ -83,8 +97,8 @@ function NewForm({ add }) {
   );
 }
 let focus;
-export default function Form({ update, remove, ...data }) {
-  if (data.name === "add") return <NewForm add={update} />;
+export default function FormHook({ update, remove, ...data }) {
+  if (data.name === "add") return <NewFormHook add={update} />;
 
   const [{ backends }] = useGeneral();
   const backendOptions = backends.map(({ name, base_url }) => ({
@@ -98,29 +112,30 @@ export default function Form({ update, remove, ...data }) {
   }));
 
   const [name, setName] = useState(data.name);
+  const initialName = useRef(data.name);
   const nameInput = useRef();
 
+  const hookNames = useHookNames();
+  const [nameConflict, setNameConflict] = useState(false);
+  const handleSetName = (name) => {
+    setNameConflict(name !== initialName.current && hookNames.has(name));
+    setName(name.trim());
+  };
+
   useEffect(() => {
     if (focus) {
       nameInput.current.focus();
     }
   }, []);
 
-  const timeout = useRef(false);
+  const timeout = useRef();
   useEffect(() => {
-    if (timeout.current === false) {
-      timeout.current = 0;
-      return;
-    }
-
     clearTimeout(timeout.current);
+    if (!name || nameConflict) return;
     timeout.current = setTimeout(() => update({ ...data, name }), 500);
   }, [name]);
 
-  useEffect(() => {
-    timeout.current = false;
-    setName(data.name);
-  }, [data.name]);
+  useEffect(() => setName(data.name), [data.name]);
 
   return (
     <div
@@ -138,9 +153,14 @@ export default function Form({ update, remove, ...data }) {
       >
         <TextControl
           ref={nameInput}
-          label={__("Bound ID", "wpct-erp-forms")}
+          label={__("Name", "wpct-erp-forms")}
+          help={
+            nameConflict
+              ? __("This name is already in use", "wpct-erp-forms")
+              : ""
+          }
           value={name}
-          onChange={setName}
+          onChange={handleSetName}
           onFocus={() => (focus = true)}
           onBlur={() => (focus = false)}
           __nextHasNoMarginBottom
@@ -179,7 +199,7 @@ export default function Form({ update, remove, ...data }) {
           </label>
           <FormPipes
             formId={data.form_id}
-            pipes={data.pipes}
+            pipes={data.pipes || []}
             setPipes={(pipes) => update({ ...data, pipes })}
           />
         </div>
diff --git a/src/RestApiSettings/FormHooks/index.jsx b/src/RestApiSettings/FormHooks/index.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..7407c26adebf376b80edc98fe4e540d372e2f49d
--- /dev/null
+++ b/src/RestApiSettings/FormHooks/index.jsx
@@ -0,0 +1,70 @@
+// vendor
+import React from "react";
+import { __ } from "@wordpress/i18n";
+import { TabPanel } from "@wordpress/components";
+
+// source
+import FormHook from "./FormHook";
+
+export default function FormHooks({ hooks, setHooks }) {
+  const tabs = hooks
+    .map(({ backend, endpoint, form_id, name, pipes }) => ({
+      name,
+      title: name,
+      form_id,
+      endpoint,
+      backend,
+      pipes,
+    }))
+    .concat([
+      {
+        title: __("Add Form", "wpct-erp-forms"),
+        name: "add",
+      },
+    ]);
+
+  const updateHook = (index, data) => {
+    if (index === -1) index = forms.length;
+    const newHooks = hooks
+      .slice(0, index)
+      .concat([data])
+      .concat(hooks.slice(index + 1, hooks.length));
+    setHooks(newHooks);
+  };
+
+  const removeHook = ({ name }) => {
+    const index = hooks.findIndex((h) => h.name === name);
+    const newHooks = hooks.slice(0, index).concat(hooks.slice(index + 2));
+    setHooks(newHooks);
+  };
+
+  return (
+    <div style={{ width: "100%" }}>
+      <label
+        className="components-base-control__label"
+        style={{
+          fontSize: "11px",
+          textTransform: "uppercase",
+          fontWeight: 500,
+          marginBottom: "calc(8px)",
+        }}
+      >
+        {__("Form Hooks", "wpct-erp-forms")}
+      </label>
+      <TabPanel tabs={tabs}>
+        {(hook) => (
+          <FormHook
+            {...hook}
+            remove={removeHook}
+            update={(data) =>
+              updateHook(
+                hooks.findIndex(({ name }) => name === hook.name),
+                data
+              )
+            }
+          />
+        )}
+      </TabPanel>
+    </div>
+  );
+}
diff --git a/src/RestApiSettings/Forms/index.jsx b/src/RestApiSettings/Forms/index.jsx
deleted file mode 100644
index d113d28649576572d4f38df927f0ac354ddfafe7..0000000000000000000000000000000000000000
--- a/src/RestApiSettings/Forms/index.jsx
+++ /dev/null
@@ -1,73 +0,0 @@
-// vendor
-import React from "react";
-import { __ } from "@wordpress/i18n";
-import { TabPanel } from "@wordpress/components";
-
-// source
-import Form from "./Form";
-
-export default function Forms({ forms, setForms }) {
-  const tabs = forms
-    .map(({ backend, endpoint, form_id, ref, pipes }) => ({
-      name: ref,
-      title: ref,
-      form_id,
-      endpoint,
-      backend,
-      pipes,
-    }))
-    .concat([
-      {
-        title: __("Add Form", "wpct-erp-forms"),
-        name: "add",
-      },
-    ]);
-
-  const updateForm = (index, data) => {
-    data = { ...data, ref: data.name };
-    delete data.name;
-
-    if (index === -1) index = forms.length;
-    const newForms = forms
-      .slice(0, index)
-      .concat([data])
-      .concat(forms.slice(index + 1, forms.length));
-    setForms(newForms);
-  };
-
-  const removeForm = ({ name }) => {
-    const index = forms.findIndex((f) => f.ref === name);
-    const newForms = forms.slice(0, index).concat(forms.slice(index + 2));
-    setForms(newForms);
-  };
-
-  return (
-    <div style={{ width: "100%" }}>
-      <label
-        className="components-base-control__label"
-        style={{
-          fontSize: "11px",
-          textTransform: "uppercase",
-          fontWeight: 500,
-          marginBottom: "calc(8px)",
-        }}
-      >
-        {__("Forms", "wpct-erp-forms")}
-      </label>
-      <TabPanel tabs={tabs}>
-        {(form) => (
-          <Form
-            {...form}
-            remove={removeForm}
-            update={(newForm) =>
-              updateForm(
-                forms.findIndex(({ ref }) => ref === form.name),
-                newForm
-              )
-            }
-          />
-        )}
-      </TabPanel>
-    </div>
-  );
-}
diff --git a/src/RestApiSettings/index.jsx b/src/RestApiSettings/index.jsx
index 9a74ac85377da911dfa59b034bbccd5fd8c2a6d5..b27d1f06a477e9a068e4cbc6e0bd6a9c6071dfec 100644
--- a/src/RestApiSettings/index.jsx
+++ b/src/RestApiSettings/index.jsx
@@ -11,10 +11,10 @@ import {
 
 // source
 import { useRestApi } from "../providers/Settings";
-import Forms from "./Forms";
+import FormHooks from "./FormHooks";
 
 export default function RestApiSettings() {
-  const [{ forms }, save] = useRestApi();
+  const [{ form_hooks: hooks }, save] = useRestApi();
   return (
     <Card size="large" style={{ height: "fit-content" }}>
       <CardHeader>
@@ -22,7 +22,10 @@ export default function RestApiSettings() {
       </CardHeader>
       <CardBody>
         <PanelRow>
-          <Forms forms={forms} setForms={(forms) => save({ forms })} />
+          <FormHooks
+            hooks={hooks}
+            setHooks={(form_hooks) => save({ form_hooks })}
+          />
         </PanelRow>
       </CardBody>
     </Card>
diff --git a/src/RpcApiSettings/Forms/Form.jsx b/src/RpcApiSettings/FormHooks/FormHook.jsx
similarity index 77%
rename from src/RpcApiSettings/Forms/Form.jsx
rename to src/RpcApiSettings/FormHooks/FormHook.jsx
index 0e51fce2e1a7e24e4f9ba9e18604b85eff359d3f..e60a76bb355b8c28ad511ae34c92c78ccd7252c1 100644
--- a/src/RpcApiSettings/Forms/Form.jsx
+++ b/src/RpcApiSettings/FormHooks/FormHook.jsx
@@ -7,9 +7,10 @@ import { useState, useRef, useEffect } from "@wordpress/element";
 // source
 import { useForms } from "../../providers/Forms";
 import { useGeneral } from "../../providers/Settings";
+import useHookNames from "../../hooks/useHookNames";
 import FormPipes from "../../FormPipes";
 
-function NewForm({ add }) {
+function NewFormHook({ add }) {
   const [{ backends }] = useGeneral();
   const backendOptions = backends.map(({ name, base_url }) => ({
     label: name,
@@ -21,14 +22,22 @@ function NewForm({ add }) {
     value: id,
   }));
 
+  const hookNames = useHookNames();
+
   const [name, setName] = useState("");
   const [backend, setBackend] = useState("");
   const [model, setModel] = useState("");
   const [formId, setFormId] = useState("");
+  const [nameConflict, setNameConflict] = useState(false);
+
+  const handleSetName = (name) => {
+    setNameConflict(hookNames.has(name));
+    setName(name.trim());
+  };
 
   const onClick = () => add({ name, backend, model, form_id: formId });
 
-  const disabled = !(name, backend, model, formId);
+  const disabled = !(name && backend && model && formId && !nameConflict);
 
   return (
     <div
@@ -45,9 +54,14 @@ function NewForm({ add }) {
         }}
       >
         <TextControl
-          label={__("Bound ID", "wpct-erp-forms")}
+          label={__("Name", "wpct-erp-forms")}
+          help={
+            nameConflict
+              ? __("This name is already in use", "wpct-erp-forms")
+              : ""
+          }
           value={name}
-          onChange={setName}
+          onChange={handleSetName}
           __nextHasNoMarginBottom
         />
         <SelectControl
@@ -84,8 +98,8 @@ function NewForm({ add }) {
 }
 
 let focus;
-export default function Form({ update, remove, ...data }) {
-  if (data.name === "add") return <NewForm add={update} />;
+export default function FormHook({ update, remove, ...data }) {
+  if (data.name === "add") return <NewFormHook add={update} />;
 
   const [{ backends }] = useGeneral();
   const backendOptions = backends.map(({ name, base_url }) => ({
@@ -99,29 +113,30 @@ export default function Form({ update, remove, ...data }) {
   }));
 
   const [name, setName] = useState(data.name);
+  const initialName = useRef(data.name);
   const nameInput = useRef();
 
+  const hookNames = useHookNames();
+  const [nameConflict, setNameConflict] = useState(false);
+  const handleSetName = (name) => {
+    setNameConflict(name !== initialName.current && hookNames.has(name));
+    setName(name.trim());
+  };
+
   useEffect(() => {
     if (focus) {
       nameInput.current.focus();
     }
   }, []);
 
-  const timeout = useRef(false);
+  const timeout = useRef();
   useEffect(() => {
-    if (timeout.current === false) {
-      timeout.current = 0;
-      return;
-    }
-
     clearTimeout(timeout.current);
+    if (!name || nameConflict) return;
     timeout.current = setTimeout(() => update({ ...data, name }), 500);
   }, [name]);
 
-  useEffect(() => {
-    timeout.current = false;
-    setName(data.name);
-  }, [data.name]);
+  useEffect(() => setName(data.name), [data.name]);
 
   return (
     <div
@@ -139,12 +154,17 @@ export default function Form({ update, remove, ...data }) {
       >
         <TextControl
           ref={nameInput}
-          label={__("Bound ID", "wpct-erp-forms")}
+          label={__("Name", "wpct-erp-forms")}
+          help={
+            nameConflict
+              ? __("This name is already in use", "wpct-erp-forms")
+              : ""
+          }
           value={name}
-          onChange={setName}
+          onChange={handleSetName}
           onFocus={() => (focus = true)}
           onBlur={() => (focus = false)}
-          __nextHasNoMarginBottom={true}
+          __nextHasNoMarginBottom
         />
         <SelectControl
           label={__("Backend", "wpct-erp-forms")}
@@ -157,7 +177,7 @@ export default function Form({ update, remove, ...data }) {
           label={__("Model", "wpct-erp-forms")}
           value={data.model}
           onChange={(model) => update({ ...data, model })}
-          __nextHasNoMarginBottom={true}
+          __nextHasNoMarginBottom
         />
         <SelectControl
           label={__("Form", "wpct-erp-forms")}
@@ -180,7 +200,7 @@ export default function Form({ update, remove, ...data }) {
           </label>
           <FormPipes
             formId={data.form_id}
-            pipes={data.pipes}
+            pipes={data.pipes || []}
             setPipes={(pipes) => update({ ...data, pipes })}
           />
         </div>
diff --git a/src/RpcApiSettings/FormHooks/index.jsx b/src/RpcApiSettings/FormHooks/index.jsx
new file mode 100644
index 0000000000000000000000000000000000000000..2d199c395d6693a6342d347752e5dd9fc2727c29
--- /dev/null
+++ b/src/RpcApiSettings/FormHooks/index.jsx
@@ -0,0 +1,70 @@
+// vendor
+import React from "react";
+import { __ } from "@wordpress/i18n";
+import { TabPanel } from "@wordpress/components";
+
+// source
+import FormHook from "./FormHook";
+
+export default function FormHooks({ hooks, setHooks }) {
+  const tabs = hooks
+    .map(({ backend, model, form_id, name, pipes }) => ({
+      name,
+      title: name,
+      form_id,
+      model,
+      backend,
+      pipes,
+    }))
+    .concat([
+      {
+        title: __("Add Form", "wpct-erp-forms"),
+        name: "add",
+      },
+    ]);
+
+  const updateHook = (index, data) => {
+    if (index === -1) index = hooks.length;
+    const newHooks = hooks
+      .slice(0, index)
+      .concat([data])
+      .concat(hooks.slice(index + 1, hooks.length));
+    setHooks(newHooks);
+  };
+
+  const removeHook = ({ name }) => {
+    const index = hooks.findIndex((h) => h.name === name);
+    const newHooks = hooks.slice(0, index).concat(hooks.slice(index + 2));
+    setHooks(newHooks);
+  };
+
+  return (
+    <div style={{ width: "100%" }}>
+      <label
+        className="components-base-control__label"
+        style={{
+          fontSize: "11px",
+          textTransform: "uppercase",
+          fontWeight: 500,
+          marginBottom: "calc(8px)",
+        }}
+      >
+        {__("Form Hooks", "wpct-erp-forms")}
+      </label>
+      <TabPanel tabs={tabs}>
+        {(hook) => (
+          <FormHook
+            {...hook}
+            remove={removeHook}
+            update={(data) =>
+              updateHook(
+                hooks.findIndex(({ name }) => name === hook.name),
+                data
+              )
+            }
+          />
+        )}
+      </TabPanel>
+    </div>
+  );
+}
diff --git a/src/RpcApiSettings/Forms/index.jsx b/src/RpcApiSettings/Forms/index.jsx
deleted file mode 100644
index fb1baff861ecf556e55dee9518a3ee671b4f0bde..0000000000000000000000000000000000000000
--- a/src/RpcApiSettings/Forms/index.jsx
+++ /dev/null
@@ -1,73 +0,0 @@
-// vendor
-import React from "react";
-import { __ } from "@wordpress/i18n";
-import { TabPanel } from "@wordpress/components";
-
-// source
-import Form from "./Form";
-
-export default function Forms({ forms, setForms }) {
-  const tabs = forms
-    .map(({ backend, model, form_id, ref, pipes }) => ({
-      name: ref,
-      title: ref,
-      form_id,
-      model,
-      backend,
-      pipes,
-    }))
-    .concat([
-      {
-        title: __("Add Form", "wpct-erp-forms"),
-        name: "add",
-      },
-    ]);
-
-  const updateForm = (index, data) => {
-    data = { ...data, ref: data.name };
-    delete data.name;
-
-    if (index === -1) index = forms.length;
-    const newForms = forms
-      .slice(0, index)
-      .concat([data])
-      .concat(forms.slice(index + 1, forms.length));
-    setForms(newForms);
-  };
-
-  const removeForm = ({ name }) => {
-    const index = forms.findIndex((f) => f.ref === name);
-    const newForms = forms.slice(0, index).concat(forms.slice(index + 2));
-    setForms(newForms);
-  };
-
-  return (
-    <div style={{ width: "100%" }}>
-      <label
-        className="components-base-control__label"
-        style={{
-          fontSize: "11px",
-          textTransform: "uppercase",
-          fontWeight: 500,
-          marginBottom: "calc(8px)",
-        }}
-      >
-        {__("Forms", "wpct-erp-forms")}
-      </label>
-      <TabPanel tabs={tabs}>
-        {(form) => (
-          <Form
-            {...form}
-            remove={removeForm}
-            update={(newForm) =>
-              updateForm(
-                forms.findIndex(({ ref }) => ref === form.name),
-                newForm
-              )
-            }
-          />
-        )}
-      </TabPanel>
-    </div>
-  );
-}
diff --git a/src/RpcApiSettings/index.jsx b/src/RpcApiSettings/index.jsx
index b59ff6749d3aacea1af49aa43e9af3d60268971a..9bc69f3c9d5dc43f9f1f7f2a6ba06e579053fb9d 100644
--- a/src/RpcApiSettings/index.jsx
+++ b/src/RpcApiSettings/index.jsx
@@ -13,13 +13,14 @@ import {
 
 // source
 import { useRpcApi } from "../providers/Settings";
-import Forms from "./Forms";
+import FormHooks from "./FormHooks";
 
 export default function RpcApiSettings() {
-  const [{ endpoint, user, password, database, forms }, save] = useRpcApi();
+  const [{ endpoint, user, password, database, form_hooks: hooks }, save] =
+    useRpcApi();
 
   const update = (field) =>
-    save({ endpoint, user, password, database, forms, ...field });
+    save({ endpoint, user, password, database, form_hooks: hooks, ...field });
 
   return (
     <Card size="large" style={{ height: "fit-content" }}>
@@ -61,7 +62,10 @@ export default function RpcApiSettings() {
         </PanelRow>
         <Spacer paddingY="calc(8px)" />
         <PanelRow>
-          <Forms forms={forms} setForms={(forms) => update({ forms })} />
+          <FormHooks
+            hooks={hooks}
+            setHooks={(form_hooks) => update({ form_hooks })}
+          />
         </PanelRow>
       </CardBody>
     </Card>
diff --git a/src/hooks/useFormFields.js b/src/hooks/useFormFields.js
index dfe491aee7dfde6915365d6c622e0d60c8618d6d..f1d966fac7f133f7b7bf0052618c7d01c2b53d3e 100644
--- a/src/hooks/useFormFields.js
+++ b/src/hooks/useFormFields.js
@@ -1,22 +1,15 @@
 // vendor
-import { __ } from "@wordpress/i18n";
-import apiFetch from "@wordpress/api-fetch";
-import { useState, useEffect } from "@wordpress/element";
+import { useMemo } from "@wordpress/element";
 
-export default function useFormFields({ formId }) {
-  const [loading, setLoading] = useState();
-  const [fields, setFields] = useState([]);
+// source
+import { useForms } from "../providers/Forms";
 
-  useEffect(() => {
-    apiFetch({
-      path: `${window.wpApiSettings.root}wpct/v1/erp-forms/form/${formId}`,
-      headers: {
-        "X-WP-Nonce": wpApiSettings.nonce,
-      },
-    })
-      .then((fields) => setFields(fields))
-      .finally(() => setLoading(false));
-  }, []);
+export default function useFormFields({ formId }) {
+  const forms = useForms();
 
-  return { loading, fields };
+  return useMemo(() => {
+    const form = forms.find(({ id }) => id == formId);
+    if (!form) return [];
+    return form.fields.map(({ name, label }) => ({ name, label }));
+  }, [forms]);
 }
diff --git a/src/hooks/useHookNames.js b/src/hooks/useHookNames.js
new file mode 100644
index 0000000000000000000000000000000000000000..97bfb5a762b9460d01f2b057e879d20e4e57debc
--- /dev/null
+++ b/src/hooks/useHookNames.js
@@ -0,0 +1,14 @@
+// vendor
+import { useMemo } from "@wordpress/element";
+
+// source
+import { useRestApi, useRpcApi } from "../providers/Settings";
+
+export default function useHookNames() {
+  const [{ form_hooks: restHooks }] = useRestApi();
+  const [{ form_hooks: rpcHooks }] = useRpcApi();
+
+  return useMemo(() => {
+    return new Set(restHooks.concat(rpcHooks).map(({ name }) => name));
+  }, [restHooks, rpcHooks]);
+}
diff --git a/src/providers/Settings.jsx b/src/providers/Settings.jsx
index c0864147ef317bcd85c7b472671d9e90952440c4..049e09702297677748963b45c78d103f74088792 100644
--- a/src/providers/Settings.jsx
+++ b/src/providers/Settings.jsx
@@ -20,14 +20,14 @@ const defaultSettings = {
     backends: [],
   },
   "rest-api": {
-    forms: [],
+    form_hooks: [],
   },
   "rpc-api": {
     endpoint: "/jsonrpc",
     database: "crm.lead",
     user: "admin",
     password: "admin",
-    forms: [],
+    form_hooks: [],
   },
 };
 
diff --git a/wpct-erp-forms.php b/wpct-erp-forms.php
index 13fa46471397050b8e2f39452a98e1a0db98b516..570ce44c16f1db13b6a66f166d6522a14e0f9d74 100755
--- a/wpct-erp-forms.php
+++ b/wpct-erp-forms.php
@@ -21,6 +21,13 @@ if (!defined('ABSPATH')) {
     exit();
 }
 
+/**
+ * Handle plugin version
+ *
+ * @since 0.0.1
+ *
+ * @var string WPCT_ERP_FORMS_VERSION Current plugin versio.
+ */
 define('WPCT_ERP_FORMS_VERSION', '2.0.3');
 
 require_once 'abstracts/class-singleton.php';
@@ -38,18 +45,74 @@ require_once 'includes/class-rest-controller.php';
 
 class Wpct_Erp_Forms extends BasePlugin
 {
-    private $_integrations = [];
-    private $_refs = null;
-
+    /**
+     * Handle plugin active integrations.
+     *
+     * @since 1.0.0
+     *
+     * @var array $_integrations
+     */
+    private $_integrations = null;
+
+    /**
+     * Handle plugin name.
+     *
+     * @since 1.0.0
+     *
+     * @var string $name Plugin name.
+     */
     public static $name = 'Wpct ERP Forms';
+
+    /**
+     * Handle plugin textdomain.
+     *
+     * @since 1.0.0
+     *
+     * @var string $textdomain Plugin text domain.
+     */
     public static $textdomain = 'wpct-erp-forms';
 
+    /**
+     * Handle plugin menu class name.
+     *
+     * @since 1.0.0
+     *
+     * @var string $menu_class Plugin menu class name.
+     */
     protected static $menu_class = '\WPCT_ERP_FORMS\Menu';
 
+    /**
+     * Starts the plugin.
+     *
+     * @since 3.0.0
+     */
+    public static function start()
+    {
+        return self::get_instance();
+    }
+
+    /**
+     * Initialize integrations, REST Controller and setup plugin hooks.
+     *
+     * @since 1.0.0
+     */
     protected function __construct()
     {
         parent::__construct();
+        REST_Controller::setup();
 
+        $this->load_integrations();
+        $this->wp_hooks();
+        $this->custom_hooks();
+    }
+
+    /**
+     * Load plugin integrations.
+     *
+     * @since 3.0.0
+     */
+    private function load_integrations()
+    {
         if (
             apply_filters(
                 'wpct_is_plugin_active',
@@ -69,7 +132,16 @@ class Wpct_Erp_Forms extends BasePlugin
             require_once 'includes/integrations/gf/class-integration.php';
             $this->_integrations['gf'] = GFIntegration::get_instance();
         }
+    }
 
+    /**
+     * Bound plugin to wp hooks.
+     *
+     * @since 3.0.0
+     */
+    private function wp_hooks()
+    {
+        // Add link to submenu page on plugins page
         add_filter(
             'plugin_action_links',
             function ($links, $file) {
@@ -87,6 +159,7 @@ class Wpct_Erp_Forms extends BasePlugin
             2
         );
 
+        // Patch http bridge settings to erp forms settings
         add_filter('option_wpct-erp-forms_general', function ($value) {
             $http_setting = Settings::get_setting(
                 'wpct-http-bridge',
@@ -99,6 +172,7 @@ class Wpct_Erp_Forms extends BasePlugin
             return $value;
         });
 
+        // Syncronize erp form settings with http bridge settings
         add_action(
             'updated_option',
             function ($option, $from, $to) {
@@ -117,139 +191,151 @@ class Wpct_Erp_Forms extends BasePlugin
             3
         );
 
+        // Enqueue plugin admin client scripts
+        add_action('admin_enqueue_scripts', function ($admin_page) {
+            $this->admin_enqueue_scripts($admin_page);
+        });
+    }
+
+    /**
+     * Add plugin custom filters.
+     *
+     * @since 3.0.0
+     */
+    private function custom_hooks()
+    {
+        // Return registerd form hooks
         add_filter(
-            'wpct_erp_forms_form_ref',
+            'wpct_erp_forms_form_hooks',
             function ($null, $form_id) {
-                return $this->get_form_ref($form_id);
+                return $this->get_form_hooks($form_id);
             },
             10,
             2
         );
 
-        add_filter(
-            'option_wpct-erp-forms_rest-api',
-            function ($setting) {
-                return $this->populate_refs($setting);
-            },
-            10,
-            1
-        );
-
-        add_filter(
-            'option_wpct-erp-forms_rpc-api',
-            function ($setting) {
-                return $this->populate_refs($setting);
-            },
-            10,
-            1
-        );
-
-        add_action(
-            'updated_option',
-            function ($option, $from, $to) {
-                $this->on_option_updated($option, $to);
-            },
-            90,
-            3
-        );
-
-        add_action(
-            'add_option',
-            function ($option, $value) {
-                $this->on_option_updated($option, $value);
-            },
-            90,
-            3
-        );
+        // Return pair plugin registered forms datums
+        add_filter('wpct_erp_forms_forms', function ($null) {
+            $integration = $this->get_integration();
+            if (!$integration) {
+                return $null;
+            }
 
-        add_action('admin_enqueue_scripts', function ($admin_page) {
-            $this->enqueue_scripts($admin_page);
+            return $integration->get_forms();
         });
 
-        new REST_Controller();
-    }
+        // Return current pair plugin form representation
+        // If $form_id is passed, retrives form by ID.
+        add_filter('wpct_erp_forms_form', function ($null, $form_id = null) {
+            $integration = $this->get_integration();
+            if (!$integration) {
+                return $null;
+            }
 
-    public function init()
-    {
-    }
+            if ($form_id) {
+                return $integration->get_form_by_id($form_id);
+            } else {
+                return $integration->get_form();
+            }
+        });
 
-    public static function activate()
-    {
-    }
+        // Return the current submission data
+        add_filter('wpct_erp_forms_submission', function ($null) {
+            $integration = $this->get_integration();
+            if (!$integration) {
+                return $null;
+            }
 
-    public static function deactivate()
-    {
-    }
+            return $integration->get_submission();
+        });
 
-    private function get_form_refs()
-    {
-        if (empty($this->_refs)) {
-            $this->_refs = get_option('wpct-erp-forms_refs', []);
-            if (!is_array($this->_refs)) {
-                $this->_refs = [];
+        // Return the current submission uploaded files
+        add_filter('wpct_erp_forms_uploads', function ($null) {
+            $integration = $this->get_integration();
+            if (!$integration) {
+                return $null;
             }
-        }
 
-        return $this->_refs;
+            return $integration->get_uploads();
+        });
     }
 
-    private function set_form_refs($refs)
+    /**
+     * Initialize the plugin on wp init.
+     *
+     * @since 1.0.0
+     */
+    public function init()
     {
-        $this->_refs = $refs;
-        update_option('wpct-erp-forms_refs', $refs);
     }
 
-    public function get_form_ref($form_id)
+    /**
+     * Callback to activation hook.
+     *
+     * @since 1.0.0
+     */
+    public static function activate()
     {
-        $refs = $this->get_form_refs();
-        foreach ($refs as $ref_id => $ref) {
-            if ((string) $ref_id === (string) $form_id) {
-                return $ref;
-            }
-        }
-
-        return null;
     }
 
-    public function set_form_ref($form_id, $ref)
+    /**
+     * Callback to deactivation hook.
+     *
+     * @since 1.0.0
+     */
+    public static function deactivate()
     {
-        $refs = $this->get_form_refs();
-        $refs[$form_id] = $ref;
-        $this->set_form_refs($refs);
     }
 
-    private function populate_refs($setting)
+    /**
+     * Return the current integration.
+     *
+     * @since 3.0.0
+     *
+     * @return object $integration
+     */
+    private function get_integration()
     {
-        $refs = $this->get_form_refs();
-        for ($i = 0; $i < count($setting['forms']); $i++) {
-            $form = $setting['forms'][$i];
-            if (!isset($refs[$form['form_id']])) {
-                continue;
+        foreach ($this->_integrations as $key => $integration) {
+            if ($integration) {
+                return $integration;
             }
-            $form['ref'] = $refs[$form['form_id']];
-            $setting['forms'][$i] = $form;
         }
-
-        return $setting;
     }
 
-    private function on_option_updated($option, $value)
+    /**
+     * Return form API hooks.
+     *
+     * @since 3.0.0
+     *
+     * @return array $hooks Array with hooks.
+     */
+    private function get_form_hooks($form_id)
     {
-        $settings = ['wpct-erp-forms_rest-api', 'wpct-erp-forms_rpc-api'];
-        if (in_array($option, $settings)) {
-            $refs = $this->get_form_refs();
-            foreach ($value['forms'] as $form) {
-                if (empty($form['form_id'])) {
-                    continue;
+        $rest_api = Settings::get_setting('wpct-erp-forms', 'rest-api');
+        $rpc_api = Settings::get_setting('wpct-erp-forms', 'rpc-api');
+
+        return array_reduce(
+            array_merge($rest_api['form_hooks'], $rpc_api['form_hooks']),
+            function ($hooks, $hook) use ($form_id) {
+                if ((int) $hook['form_id'] === (int) $form_id) {
+                    $hooks[$hook['name']] = $hook;
                 }
 
-                $refs[$form['form_id']] = $form['ref'];
-            }
-            $this->set_form_refs($refs);
-        }
+                return $hooks;
+            },
+            []
+        );
     }
 
-    private function enqueue_scripts($admin_page)
+    /**
+     * Enqueue admin client scripts
+     *
+     * @since 3.0.0
+     *
+     * @param string $admin_page Current admin page.
+     */
+    private function admin_enqueue_scripts($admin_page)
     {
         if ('settings_page_wpct-erp-forms' !== $admin_page) {
             return;
@@ -276,10 +362,5 @@ class Wpct_Erp_Forms extends BasePlugin
     }
 }
 
-add_action(
-    'plugins_loaded',
-    function () {
-        $plugin = Wpct_Erp_Forms::get_instance();
-    },
-    9
-);
+// Setup plugin on wp plugins_loaded hook
+add_action('plugins_loaded', ['\WPCT_ERP_FORMS\Wpct_Erp_Forms', 'start'], 9);
diff --git a/wpct-http-bridge b/wpct-http-bridge
index 3ba30c173cbdc7f25265142e214a3a1cdb2b4030..758f1d2f4e114c9c43c46ffa3aca850659fb2c04 160000
--- a/wpct-http-bridge
+++ b/wpct-http-bridge
@@ -1 +1 @@
-Subproject commit 3ba30c173cbdc7f25265142e214a3a1cdb2b4030
+Subproject commit 758f1d2f4e114c9c43c46ffa3aca850659fb2c04