diff --git a/CRM/FormProcessor/BAO/FormProcessor.php b/CRM/FormProcessor/BAO/FormProcessor.php
index a6d963e005ee3a3db3fa4628e295d0057a079cb8..b355b1d771511d9633d5d72de54ed927847d09bd 100644
--- a/CRM/FormProcessor/BAO/FormProcessor.php
+++ b/CRM/FormProcessor/BAO/FormProcessor.php
@@ -100,6 +100,8 @@
 
 		// First delete all inputs
 		CRM_FormProcessor_BAO_FormProcessorInput::deleteWithFormProcessorId($id);
+		// And all actions
+		CRM_FormProcessor_BAO_FormProcessorAction::deleteWithFormProcessorId($id);
 
     $rule = new CRM_FormProcessor_BAO_FormProcessor();
     $rule->id = $id;
diff --git a/CRM/FormProcessor/BAO/FormProcessorAction.php b/CRM/FormProcessor/BAO/FormProcessorAction.php
index 8ba8d60a1f806831fd0eeaa614e28e5a4343a4a5..d7600d9194bea3b824a47418d455391f62e31807 100644
--- a/CRM/FormProcessor/BAO/FormProcessorAction.php
+++ b/CRM/FormProcessor/BAO/FormProcessorAction.php
@@ -33,7 +33,7 @@ class CRM_FormProcessor_BAO_FormProcessorAction extends CRM_FormProcessor_DAO_Fo
       self::storeValues($action, $row);
       if (!empty($row['form_processor_id'])) {
       	$provider = form_processor_get_action_provider();
-				$action_type = $provider->getActionByName($name);
+				$action_type = $provider->getActionByName($row['type']);
 				
 				if ($action_type) {
 					$configuration = $action_type->getDefaultConfiguration();
@@ -44,12 +44,20 @@ class CRM_FormProcessor_BAO_FormProcessorAction extends CRM_FormProcessor_DAO_Fo
 						$row['configuration'] = array();
 					}
 					foreach($row['configuration'] as $name => $value) {
-						$configuration->set($name, $value);
+						$configuration->setParameter($name, $value);
 					}
 					$action_type->setConfiguration($configuration);
 					
-					$row['type'] = $action_type->toArray();
+					$row['type'] = $action_type;
 				}
+				
+				if (isset($row['mapping']) && is_string($row['mapping'])) {
+						$row['mapping'] = json_decode($row['mapping'], true);
+					}
+					if (empty($row['mapping']) || !is_array($row['mapping'])) {
+						$row['mapping'] = array();
+					}
+				
         $result[$row['id']] = $row;
       } else {
         //invalid input because no there is no form processor
@@ -88,9 +96,13 @@ class CRM_FormProcessor_BAO_FormProcessorAction extends CRM_FormProcessor_DAO_Fo
         $action->$key = $value;
       }
     }
+
 		if (is_array($action->configuration)) {
 			$action->configuration = json_encode($action->configuration);
 		}
+		if (is_array($action->mapping)) {
+			$action->mapping = json_encode($action->mapping);
+		}
     $action->save();
     self::storeValues($action, $result);
 		
diff --git a/CRM/FormProcessor/BAO/FormProcessorInput.php b/CRM/FormProcessor/BAO/FormProcessorInput.php
index 415cb72e7a77f49a194195f14e3f2d49b94bc16d..1191b622e8524ecf86905c9dd34f5882002e0a7b 100644
--- a/CRM/FormProcessor/BAO/FormProcessorInput.php
+++ b/CRM/FormProcessor/BAO/FormProcessorInput.php
@@ -45,7 +45,7 @@ class CRM_FormProcessor_BAO_FormProcessorInput extends CRM_FormProcessor_DAO_For
 					}
 					$type->setConfiguration($configuration);
 					
-					$row['type'] = $type->toArray();
+					$row['type'] = $type;
 				}
         $result[$row['id']] = $row;
       } else {
diff --git a/CRM/FormProcessor/DAO/FormProcessorAction.php b/CRM/FormProcessor/DAO/FormProcessorAction.php
index 4b29fde389410e61e0cd2c0d179c108903634503..aeef77ecf525c17f06ea6e53f2d9361fb1314ca3 100644
--- a/CRM/FormProcessor/DAO/FormProcessorAction.php
+++ b/CRM/FormProcessor/DAO/FormProcessorAction.php
@@ -68,6 +68,11 @@ class CRM_FormProcessor_DAO_FormProcessorAction extends CRM_Core_DAO {
           'title' => E::ts('Configuration'),
           'type' => CRM_Utils_Type::T_TEXT,
         ),
+        'mapping' => array(
+          'name' => 'mapping',
+          'title' => E::ts('Mapping'),
+          'type' => CRM_Utils_Type::T_TEXT,
+        ),
       );
     }
     return self::$_fields;
@@ -88,6 +93,7 @@ class CRM_FormProcessor_DAO_FormProcessorAction extends CRM_Core_DAO {
         'title' => 'title',
         'type' => 'type',
         'configuration' => 'configuration',
+        'mapping' => 'mapping',
       );
     }
     return self::$_fieldKeys;
diff --git a/Civi/FormProcessor/API/Provider.php b/Civi/FormProcessor/API/Provider.php
index ca9a210e8abb08b0f2cc943af08762441f7f9473..2b54f9cfdecb3011726b0172d32bba8553ccdf40 100644
--- a/Civi/FormProcessor/API/Provider.php
+++ b/Civi/FormProcessor/API/Provider.php
@@ -6,18 +6,34 @@
  
  namespace Civi\FormProcessor\API;
  
- use \Civi\API\Provider\ProviderInterface as API_ProviderInterface;
+ use Civi\API\Event\ResolveEvent;
+ use Civi\API\Events; 
+ use Civi\API\Provider\ProviderInterface as API_ProviderInterface;
+ use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 
 /**
  * This class connects the enabled form processors to 
  * the the api interface of CiviCRM. That way the form processors 
  * could be executed over the api.
  */ 
- class Provider implements API_ProviderInterface {
+ class Provider implements API_ProviderInterface, EventSubscriberInterface {
  	
 	public function __construct() {
 		
 	}
+	
+	/**
+   * @return array
+   */
+  public static function getSubscribedEvents() {
+    return array(
+      Events::RESOLVE => array('onApiResolve'),
+    );
+  }
+	
+	public function onApiResolve(ResolveEvent $event) {
+			$event->setApiProvider($this);
+	}
  	
 	/**
    * @param array $apiRequest
@@ -28,7 +44,45 @@
    * @throws \API_Exception
    */
   public function invoke($apiRequest) {
-  	// Run the api
+  	$actionProvider = form_processor_get_action_provider();	
+  	$params = $apiRequest['params'];
+  	  	
+  	// Find the form processor
+  	$formProcessors = \CRM_FormProcessor_BAO_FormProcessor::getValues(array('name' => $apiRequest['action']));
+		if (count($formProcessors) != 1) {
+			throw new \API_Exception('Could not find a form processor');
+		}
+		$formProcessor = reset($formProcessors);;
+		
+		// Validate the parameters.
+		foreach($formProcessor['inputs'] as $input) {
+			if ($input['is_required'] && !isset($params[$input['name']])) {
+				throw new \API_Exception('Parameter '.$input['name'].' is required');
+			}
+			if (!$input['type']->validateValue($params[$input['name']])) {
+				throw new \API_Exception('Parameter '.$input['name'].' is required');
+			}
+		}
+		
+		// Execute the actions
+		$actionParams = array();
+		foreach($formProcessor['actions'] as $action) {
+			// Create a parameter bag for the action
+			$parameterBag = $actionProvider->createParameterBag();
+			foreach($action['mapping'] as $field => $mapping) {
+				$splittedMapping = explode('.', $mapping);
+				if ($splittedMapping[0] == 'input' && isset($params[$splittedMapping[1]])) {
+					$parameterBag->setParameter($field, $params[$splittedMapping[1]]);
+				} elseif ($splittedMapping[0] == 'action' && isset($actionParams[$splittedMapping[1]]) && isset($actionParams[$splittedMapping[1]][$splittedMapping[2]])) {
+					$parameterBag->setParameter($field, $actionParams[$splittedMapping[1]][$splittedMapping[2]]);
+				}
+			}
+
+			$outputBag = $action['type']->execute($parameterBag);
+			// @Todo catch the output of the action
+		}
+
+		return array('succes' => 1);
   }
 
   /**
diff --git a/ang/form_processor/ActionDialogCtrl.html b/ang/form_processor/ActionDialogCtrl.html
new file mode 100644
index 0000000000000000000000000000000000000000..f4af01cf0bb35d05438ed9a8a84feef8974c02ba
--- /dev/null
+++ b/ang/form_processor/ActionDialogCtrl.html
@@ -0,0 +1,33 @@
+<div ng-controller="ActionDialogCtrl" class="crm-block crm-form-block">
+  <div class="crm-block crm-form-block" ng-form="ActionForm" crm-ui-id-scope>
+    <div class="crm-group">
+    	
+    	<div crm-ui-field="{name: 'ActionForm.type', title: ts('Type')}">
+    		<div>{{model.action.type.title}}</div>
+  		</div>
+    	
+    	<div crm-ui-field="{name: 'ActionForm.title', title: ts('Title')}">
+      <input
+        crm-ui-id="addActionForm.title"
+        type="text"
+        name="title"
+        ng-model="model.action.title"
+        class="big crm-form-text"
+        required
+        autofocus
+        />
+	    </div>
+	    
+	    <crm-ap-action-configuration 
+	    	configuration="model.action.configuration" 
+	    	action="model.action.type"
+	    	fields="model.formProcessor.fields"
+	    	mapping="model.action.mapping"
+    	></crm-ap-action-configuration>
+
+			<button crm-icon="fa-check" ng-click="saveClick()" ng-disabled="addActionForm.$invalid">{{ts('Save and close')}}</button>
+			<button crm-icon="fa-times" ng-click="cancelClick()">{{ts('Cancel')}}</button>
+			
+    </div>
+  </div>
+</div>
diff --git a/ang/form_processor/AddActionDialogCtrl.html b/ang/form_processor/AddActionDialogCtrl.html
deleted file mode 100644
index f9090349b974eba96e9d1f13bd55653cf3680a5a..0000000000000000000000000000000000000000
--- a/ang/form_processor/AddActionDialogCtrl.html
+++ /dev/null
@@ -1,30 +0,0 @@
-<div ng-controller="ActionDialogCtrl" class="">
-  <div class="crm-block" ng-form="addActionForm" crm-ui-id-scope>
-    <div class="crm-group">
-    	
-    	<div crm-ui-field="{name: 'addActionForm.type', title: ts('Type')}">
-    		<div>{{model.action.type.title}}</div>
-  		</div>
-    	
-    	<div crm-ui-field="{name: 'addActionForm.title', title: ts('Title')}">
-      <input
-        crm-ui-id="addActionForm.title"
-        type="text"
-        name="title"
-        ng-model="model.action.title"
-        class="big crm-form-text"
-        required
-        autofocus
-        />
-	    </div>
-	    
-	    <!--crm-form-processor-type-configuration 
-	    	type=model.input.type
-    	></crm-form-processor-type-configuration-->
-
-			<button crm-icon="fa-check" ng-click="saveClick()">{{ts('Add action')}}</button>
-			<button crm-icon="fa-times" ng-click="cancelClick()">{{ts('Cancel')}}</button>
-			
-    </div>
-  </div>
-</div>
diff --git a/ang/form_processor/EditInputDialogCtrl.html b/ang/form_processor/EditInputDialogCtrl.html
deleted file mode 100644
index c81858b2650f4ccb15e94f5cc8ac3827fb1d5afe..0000000000000000000000000000000000000000
--- a/ang/form_processor/EditInputDialogCtrl.html
+++ /dev/null
@@ -1,50 +0,0 @@
-<div ng-controller="InputDialogCtrl" class="">
-  <div class="crm-block" ng-form="editInputForm" crm-ui-id-scope>
-    <div class="crm-group">
-    	
-    	<div crm-ui-field="{name: 'formProcessorDetailForm.type', title: ts('Type')}">
-    		<div>{{model.input.type.label}}</div>
-  		</div>
-    	
-    	<div crm-ui-field="{name: 'editInputForm.name', title: ts('Name')}">
-      <input
-        crm-ui-id="editInputForm.name"
-        type="text"
-        name="name"
-        ng-model="model.input.name"
-        class="big crm-form-text"
-        required
-        autofocus
-        />
-        <div ng-show="invalidName">
-        	<em>{{ts('WARNING: The name of the formprocessor is invalid (Only lowercase characters and _ are allowed).')}}</em>
-      	</div>
-      	<div ng-show="nameExists">
-        	<em>{{ts('WARNING: The name of the formprocessor already exists.')}}</em>
-      	</div>
-	    </div>
-	
-			<div crm-ui-field="{title: ts('Is required?')}">
-	      <input name="is_required" type="checkbox" ng-model="model.input.is_required" ng-true-value="'1'" ng-false-value="'0'"/>
-	 		</div>
-	 		
-	 		<div crm-ui-field="{name: 'editInputForm.default_value', title: ts('Default value')}">
-	      <input
-	        crm-ui-id="editInputForm.default_value"
-	        type="text"
-	        name="title"
-	        ng-model="model.input.default_value"
-	        class="big crm-form-text"
-	        />
-	    </div>
-	    
-	    <crm-form-processor-type-configuration 
-	    	type=model.input.type
-    	></crm-form-processor-type-configuration>
-
-			<button crm-icon="fa-check" ng-click="saveClick()">{{ts('Update input')}}</button>
-			<button crm-icon="fa-times" ng-click="cancelClick()">{{ts('Cancel')}}</button>
-			
-    </div>
-  </div>
-</div>
diff --git a/ang/form_processor/edit.html b/ang/form_processor/FormProcessorEditCtrl.html
similarity index 73%
rename from ang/form_processor/edit.html
rename to ang/form_processor/FormProcessorEditCtrl.html
index 436c7c35ad2f72661cf4ec5a2708d24be5cc7cfb..9d1298486b1c9605f342c2a96bdd7c2626bf9b77 100644
--- a/ang/form_processor/edit.html
+++ b/ang/form_processor/FormProcessorEditCtrl.html
@@ -9,11 +9,11 @@ Required vars: formProcessor
 <form name="editFormProcessorForm" unsaved-warning-form>
 <div class="crm-block crm-form-block crmFormProcessor">
 
-  <div ng-include="'~/form_processor/formProcessorDetails.html'"></div>
+  <div ng-include="'~/form_processor/FormProcessorEditCtrl/Details.html'"></div>
   
-  <div ng-include="'~/form_processor/formProcessorInputTable.html'"></div>
+  <div ng-include="'~/form_processor/FormProcessorEditCtrl/InputTable.html'"></div>
   
-  <div ng-include="'~/form_processor/formProcessorActionTable.html'"></div>
+  <div ng-include="'~/form_processor/FormProcessorEditCtrl/ActionTable.html'"></div>
 
   <div class="crm-submit-buttons">
     <button crm-icon="fa-check" ng-click="editFormProcessorForm.$setPristine(); save()" ng-disabled="editFormProcessorForm.$invalid || !isNameValid">
diff --git a/ang/form_processor/FormProcessors.js b/ang/form_processor/FormProcessorEditCtrl.js
similarity index 51%
rename from ang/form_processor/FormProcessors.js
rename to ang/form_processor/FormProcessorEditCtrl.js
index a50e55ac155b507b14760bca8ea0836a7909c5e9..7f48fe74a7264f9cce1885da8466d36d63c98cec 100644
--- a/ang/form_processor/FormProcessors.js
+++ b/ang/form_processor/FormProcessorEditCtrl.js
@@ -1,21 +1,9 @@
 (function(angular, $, _) {
 
   angular.module('form_processor').config(function($routeProvider) {
-      $routeProvider.when('/formProcessors', {
-        controller: 'FormProcessorListCtrl',
-        templateUrl: '~/form_processor/list.html',
-
-        // If you need to look up data when opening the page, list it out
-        // under "resolve".
-        resolve: {
-          formProcessors: function($route, crmApi) {
-            return crmApi('FormProcessor', 'get', {options: {limit: 0}});
-          }
-        }
-      });
       $routeProvider.when('/formProcessor/new', {
-        templateUrl: '~/form_processor/edit.html',
-        controller: 'FormProcessorCtrl',
+        templateUrl: '~/form_processor/FormProcessorEditCtrl.html',
+        controller: 'FormProcessorEditCtrl',
         resolve: {
         	apiCalls: function($route, crmApi) {
         		reqs = {};
@@ -30,8 +18,8 @@
         }
       });
       $routeProvider.when('/formProcessor/:id', {
-        templateUrl: '~/form_processor/edit.html',
-        controller: 'FormProcessorCtrl',
+        templateUrl: '~/form_processor/FormProcessorEditCtrl.html',
+        controller: 'FormProcessorEditCtrl',
         resolve: {
         	apiCalls: function($route, crmApi) {
         		var reqs = {};
@@ -47,22 +35,13 @@
     }
   );
   
-  angular.module('form_processor').directive('crmFormProcessorTypeConfiguration', function() {
-	  return {
-	    restrict: 'E',
-	    scope: {
-	      type: '=type',
-	    },
-	    templateUrl: '~/form_processor/TypeConfiguration.html',
-	  };
-	});
-  
-  angular.module('form_processor').controller('FormProcessorCtrl', function($scope, dialogService, crmApi, apiCalls) {
+  angular.module('form_processor').controller('FormProcessorEditCtrl', function($scope, dialogService, crmApi, apiCalls, $q) {
   	var ts = $scope.ts = CRM.ts(null);
 
     $scope.formProcessor = apiCalls.formProcessor; 
     $scope.locks = {name: true};
     $scope.isNameValid = false;
+    $scope.new_id = -1;
     
     $scope.inputTypes = CRM.form_processor.inputTypes;
     for(var i=0; i<$scope.inputTypes.length; i++) {
@@ -106,11 +85,13 @@
       var result = crmApi('FormProcessor', 'create', $scope.formProcessor, true);
       result.then(function(data) {
         if (data.is_error === 0 || data.is_error == '0') {
-          $scope.formProcessor.id = data.id;
+          $scope.formProcessor.id = data.id;  
+          
+          var apiCalls = [];
           
           angular.forEach($scope.deletedInputs, function(input, key) {
-          	if (input.id) {          	
-          		crmApi('FormProcessorInput', 'delete', {'id': input.id}, true);
+          	if (input.id) {
+          		apiCalls.push(crmApi('FormProcessorInput', 'delete', {'id': input.id}, true));
           	}
           });
           
@@ -118,9 +99,56 @@
           	input.form_processor_id = $scope.formProcessor.id;
           	input.configuration = input.type.configuration; 
           	input.type = input.type.name;
-          	crmApi('FormProcessorInput', 'create', input, true);
+          	apiCalls.push(crmApi('FormProcessorInput', 'create', input, true));
+          });
+          
+          angular.forEach($scope.deletedActions, function(action, key) {
+          	if (action.id) {          	
+          		apiCalls.push(crmApi('FormProcessorAction', 'delete', {'id': action.id}, true));
+          	}
+          });
+          
+          var newActions = [];
+          var actionWeight = 0;
+          angular.forEach($scope.formProcessor.actions, function(action, key) {
+          	var old_id = action.id;
+          	if (action.id < 0) {
+          		delete action.id;
+          	}
+          	action.form_processor_id = $scope.formProcessor.id; 
+          	action.type = action.type.name;
+          	action.weight = actionWeight;
+          	console.log(action);
+          	apiCalls.push(crmApi('FormProcessorAction', 'create', action, true).then(function(action_result) {
+          		action.id = action_result.id;
+          		if (old_id < 0) {
+          			newActions[old_id] = action.id;          		
+          		}
+        		}));
+          	actionWeight++;
           });
-          window.location.href = '#/formProcessors';
+          
+          // Update the mapping
+          $q.all(apiCalls).then(function(result){
+      			// We have saved the last action. 
+      			// Lets fix the mapping of the actions so that the mapping with an id < 0 
+      			// will be resolved to their new id
+	       		angular.forEach($scope.formProcessor.actions, function(action, key) {
+	       			var actionChanged = false;
+	       			angular.forEach(action.mapping, function (field, parameter) {
+	       				var splitted_field = field.split('.');
+	       				if (splitted_field[0] == 'action' && splitted_field[1] < 0) {
+	       					action.mapping[parameter] = 'action.'+newActions[splitted_field[1]]+'.'+splitted_field[2];
+	       					actionChanged = true;
+	       				}
+	       			});
+	       			if (actionChanged) {
+	       				crmApi('FormProcessorAction', 'create', action, true);	
+	       			}
+	       		});
+          });
+          
+          window.location.href = '#/formprocessors';
         }
       });
     };
@@ -138,26 +166,14 @@
     	if (!inputType) {
     		return;
     	}    	    	
-      var options = CRM.utils.adjustDialogDefaults({
-        autoOpen: false,
-        width: '40%',
-        height: 'auto',
-        title: ts('Add input')
-      });
-      var model = {
-      	formProcessor: $scope.formProcessor,
-      	input: {
-      		type: angular.copy(inputType),
-        	'name': '',
-    			'is_required': 0,
-    			'default_value': '',
-      	}	
-      };
-      dialogService.open('InputDialog', '~/form_processor/AddInputDialogCtrl.html', model, options)
-      .then(
-			function(data) {
-				$scope.formProcessor.inputs.push(data.input);
-			});
+    	var input = {
+    		'id': $scope.new_id,
+    		'type': angular.copy(inputType),
+      	'name': '',
+  			'is_required': 0,
+  			'default_value': '',
+    	};
+      $scope.editInput(input);
     };
     
     // Open a dialog for editting an input
@@ -166,13 +182,20 @@
         autoOpen: false,
         width: '40%',
         height: 'auto',
-        title: ts('Add input')
+        title: ts('Edit input')
       });
       var model = {
       	formProcessor: $scope.formProcessor,
       	input: input
       };
-      dialogService.open('InputDialog', '~/form_processor/EditInputDialogCtrl.html', model, options);
+      dialogService.open('InputDialog', '~/form_processor/InputDialogCtrl.html', model, options)
+      .then(
+			function(data) {
+				if ($scope.new_id == data.input.id) {
+					$scope.formProcessor.inputs.push(data.input);
+					$scope.new_id --;
+				}
+			});
     };
     
     $scope.removeAction = function removeAction(action) {
@@ -188,25 +211,14 @@
     	if (!actionType) {
     		return;
     	}    	    	
-      var options = CRM.utils.adjustDialogDefaults({
-        autoOpen: false,
-        width: '40%',
-        height: 'auto',
-        title: ts('Add action')
-      });
-      var model = {
-      	formProcessor: $scope.formProcessor,
-      	action: {
-      		type: angular.copy(actionType),
-        	'title': '',
-    			'configuration': angular.copy(actionType.default_configuration)
-      	}	
+      var action = {
+    		id: $scope.new_id,
+    		type: angular.copy(actionType),
+      	'title': '',
+  			'configuration': angular.copy(actionType.default_configuration),
+  			'mapping': {}
       };
-      dialogService.open('ActionDialog', '~/form_processor/AddActionDialogCtrl.html', model, options)
-      .then(
-			function(data) {
-				$scope.formProcessor.actions.push(data.action);
-			});
+      $scope.editAction(action);
     };
     
     // Open a dialog for editting an action
@@ -217,37 +229,49 @@
         height: 'auto',
         title: ts('Edit action')
       });
+      
+      $scope.updateFields($scope.formProcessor, action);
+      
       var model = {
       	formProcessor: $scope.formProcessor,
       	action: action
       };
-      dialogService.open('ActionDialog', '~/form_processor/EditActionDialogCtrl.html', model, options);
+      dialogService.open('ActionDialog', '~/form_processor/ActionDialogCtrl.html', model, options)
+      .then(function(data) {
+      	if ($scope.new_id == data.action.id) {
+					$scope.formProcessor.actions.push(data.action);
+					$scope.new_id --;
+				}
+			});
     };
-  });
   
-  angular.module('form_processor').controller('FormProcessorListCtrl', function($scope, crmApi, formProcessors) {
-    var ts = $scope.ts = CRM.ts(null);
-
-    $scope.formProcessors = formProcessors.values;
-    $scope.toggleFormProcessor = function (formProcessor) {
-      formProcessor.is_active = (formProcessor.is_active == '1') ? '0' : '1';
-      crmApi('FormProcessor', 'create', formProcessor, true)
-        .catch(function (data) {
-          formProcessor.is_active = (formProcessor.is_active == '1') ? '0' : '1'; // revert
-          $scope.$digest();
-        });
-    };
-    $scope.deleteFormProcessor = function (formProcessor) {
-      crmApi('FormProcessor', 'delete', {id: formProcessor.id}, {
-        error: function (data) {
-          CRM.alert(data.error_message, ts('Error'), 'error');
-        }
-      })
-        .then(function (data) {
-          delete formProcessors.values[formProcessor.id];
-          $scope.$digest();
-        });
-    };
+  	$scope.updateFields = function updateFields(formProcessor, selectedAction) {
+  		formProcessor.fields = [];
+  		angular.forEach(formProcessor.inputs, function(input, key) {
+  				var field = {
+  					'name': 'input.'+input.name,
+  					'label': 'Input::'+input.name
+  				};
+  				formProcessor.fields.push(field);
+			});
+			
+			var skipAfter = false;
+			angular.forEach(formProcessor.actions, function(action, key) {
+				if (selectedAction == action) {
+					skipAfter = true;
+				}
+				if (!skipAfter) {
+					angular.forEach(action.type.output_spec, function(output_field, output_field_key) {
+						var field = {
+  						'name': 'action.'+action.id+'.'+output_field.name,
+  						'label': 'Action::'+action.title+'::'+output_field.title
+  					};
+  					formProcessor.fields.push(field);
+  				});
+				}
+			});
+  	};
+  	
   });
 
 })(angular, CRM.$, CRM._);
diff --git a/ang/form_processor/formProcessorActionTable.html b/ang/form_processor/FormProcessorEditCtrl/ActionTable.html
similarity index 90%
rename from ang/form_processor/formProcessorActionTable.html
rename to ang/form_processor/FormProcessorEditCtrl/ActionTable.html
index 69cdad7ab760c0de9d8a80f89ad8299a73233776..9cabd5576dd01ad98fa82bc44f030b88e7d23e6b 100644
--- a/ang/form_processor/formProcessorActionTable.html
+++ b/ang/form_processor/FormProcessorEditCtrl/ActionTable.html
@@ -17,8 +17,8 @@ Required vars: formProcessor
 	    <td>{{action.title}}</td>
 	    <td>{{action.type.title}}</td>
 	    <td>
-	      <a crm-icon="fa-edit" class="crm-hover-button" ng-click="editAction(input)" title="{{ts('Edit')}}">{{ts('Edit')}}</a>
-	      <a crm-icon="fa-trash" class="crm-hover-button" ng-click="removeAction(input)" title="{{ts('Remove')}}">{{ts('Remove')}}</a>
+	      <a crm-icon="fa-edit" class="crm-hover-button" ng-click="editAction(action)" title="{{ts('Edit')}}">{{ts('Edit')}}</a>
+	      <a crm-icon="fa-trash" class="crm-hover-button" ng-click="removeAction(action)" title="{{ts('Remove')}}">{{ts('Remove')}}</a>
 	    </td>
 	  </tr>
   </tbody>
diff --git a/ang/form_processor/formProcessorDetails.html b/ang/form_processor/FormProcessorEditCtrl/Details.html
similarity index 100%
rename from ang/form_processor/formProcessorDetails.html
rename to ang/form_processor/FormProcessorEditCtrl/Details.html
diff --git a/ang/form_processor/formProcessorInputTable.html b/ang/form_processor/FormProcessorEditCtrl/InputTable.html
similarity index 100%
rename from ang/form_processor/formProcessorInputTable.html
rename to ang/form_processor/FormProcessorEditCtrl/InputTable.html
diff --git a/ang/form_processor/list.html b/ang/form_processor/FormProcessorListCtrl.html
similarity index 100%
rename from ang/form_processor/list.html
rename to ang/form_processor/FormProcessorListCtrl.html
diff --git a/ang/form_processor/FormProcessorListCtrl.js b/ang/form_processor/FormProcessorListCtrl.js
new file mode 100644
index 0000000000000000000000000000000000000000..4f09122983acbfa8fe0bf9a421019223d006bde6
--- /dev/null
+++ b/ang/form_processor/FormProcessorListCtrl.js
@@ -0,0 +1,44 @@
+(function(angular, $, _) {
+
+  angular.module('form_processor').config(function($routeProvider) {
+      $routeProvider.when('/formprocessors', {
+        controller: 'FormProcessorListCtrl',
+        templateUrl: '~/form_processor/FormProcessorListCtrl.html',
+
+        // If you need to look up data when opening the page, list it out
+        // under "resolve".
+        resolve: {
+          formProcessors: function($route, crmApi) {
+            return crmApi('FormProcessor', 'get', {options: {limit: 0}});
+          }
+        }
+      });
+    }
+  );
+  
+  angular.module('form_processor').controller('FormProcessorListCtrl', function($scope, crmApi, formProcessors) {
+    var ts = $scope.ts = CRM.ts(null);
+
+    $scope.formProcessors = formProcessors.values;
+    $scope.toggleFormProcessor = function (formProcessor) {
+      formProcessor.is_active = (formProcessor.is_active == '1') ? '0' : '1';
+      crmApi('FormProcessor', 'create', formProcessor, true)
+        .catch(function (data) {
+          formProcessor.is_active = (formProcessor.is_active == '1') ? '0' : '1'; // revert
+          $scope.$digest();
+        });
+    };
+    $scope.deleteFormProcessor = function (formProcessor) {
+      crmApi('FormProcessor', 'delete', {id: formProcessor.id}, {
+        error: function (data) {
+          CRM.alert(data.error_message, ts('Error'), 'error');
+        }
+      })
+        .then(function (data) {
+          delete formProcessors.values[formProcessor.id];
+          $scope.$digest();
+        });
+    };
+  });
+
+})(angular, CRM.$, CRM._);
\ No newline at end of file
diff --git a/ang/form_processor/AddInputDialogCtrl.html b/ang/form_processor/InputDialogCtrl.html
similarity index 76%
rename from ang/form_processor/AddInputDialogCtrl.html
rename to ang/form_processor/InputDialogCtrl.html
index 07b88c5e7993677c04ccda4db6205ea261030640..e68e365d9f1aa85dfce17028d6287020e3ac324f 100644
--- a/ang/form_processor/AddInputDialogCtrl.html
+++ b/ang/form_processor/InputDialogCtrl.html
@@ -1,14 +1,14 @@
 <div ng-controller="InputDialogCtrl" class="">
-  <div class="crm-block" ng-form="addInputForm" crm-ui-id-scope>
+  <div class="crm-block" ng-form="InputForm" crm-ui-id-scope>
     <div class="crm-group">
     	
     	<div crm-ui-field="{name: 'formProcessorDetailForm.type', title: ts('Type')}">
     		<div>{{model.input.type.label}}</div>
   		</div>
     	
-    	<div crm-ui-field="{name: 'addInputForm.name', title: ts('Name')}">
+    	<div crm-ui-field="{name: 'InputForm.name', title: ts('Name')}">
       <input
-        crm-ui-id="addInputForm.name"
+        crm-ui-id="InputForm.name"
         type="text"
         name="name"
         ng-model="model.input.name"
@@ -28,9 +28,9 @@
 	      <input name="is_required" type="checkbox" ng-model="model.input.is_required" ng-true-value="'1'" ng-false-value="'0'"/>
 	 		</div>
 	 		
-	 		<div crm-ui-field="{name: 'addInputForm.default_value', title: ts('Default value')}">
+	 		<div crm-ui-field="{name: 'InputForm.default_value', title: ts('Default value')}">
 	      <input
-	        crm-ui-id="addInputForm.default_value"
+	        crm-ui-id="InputForm.default_value"
 	        type="text"
 	        name="title"
 	        ng-model="model.input.default_value"
@@ -42,7 +42,7 @@
 	    	type=model.input.type
     	></crm-form-processor-type-configuration>
 
-			<button crm-icon="fa-check" ng-click="saveClick()">{{ts('Add input')}}</button>
+			<button crm-icon="fa-check" ng-click="saveClick()">{{ts('Save and Close')}}</button>
 			<button crm-icon="fa-times" ng-click="cancelClick()">{{ts('Cancel')}}</button>
 			
     </div>
diff --git a/ang/form_processor/TypeConfiguration.html b/ang/form_processor/crmFormProcessorTypeConfiguration.html
similarity index 100%
rename from ang/form_processor/TypeConfiguration.html
rename to ang/form_processor/crmFormProcessorTypeConfiguration.html
diff --git a/ang/form_processor/crmFormProcessorTypeConfiguration.js b/ang/form_processor/crmFormProcessorTypeConfiguration.js
new file mode 100644
index 0000000000000000000000000000000000000000..8bec3b1d16de58e2b0df3fd62b935788b8ee0e6d
--- /dev/null
+++ b/ang/form_processor/crmFormProcessorTypeConfiguration.js
@@ -0,0 +1,13 @@
+(function(angular, $, _) {
+	
+	angular.module('form_processor').directive('crmFormProcessorTypeConfiguration', function() {
+	  return {
+	    restrict: 'E',
+	    scope: {
+	      type: '=type',
+	    },
+	    templateUrl: '~/form_processor/crmFormProcessorTypeConfiguration.html',
+	  };
+	});
+	
+})(angular, CRM.$, CRM._);
\ No newline at end of file
diff --git a/api/v3/FormProcessor/Get.php b/api/v3/FormProcessor/Get.php
index 43bf53e8f8a83bd203f1d0b0372c92b5d268e7a8..589d0b8ab9069fc0f3e5db2fc1b4d9a47db3e33c 100644
--- a/api/v3/FormProcessor/Get.php
+++ b/api/v3/FormProcessor/Get.php
@@ -10,6 +10,14 @@
  */
 function civicrm_api3_form_processor_get($params) {
   $returnValues = CRM_FormProcessor_BAO_FormProcessor::getValues($params);
+	foreach($returnValues as $index => $formProcessor) {
+		foreach($formProcessor['inputs'] as $key => $input) {
+			$returnValues[$index]['inputs'][$key]['type'] = $input['type']->toArray();
+		}
+		foreach($formProcessor['actions'] as $key => $action) {
+			$returnValues[$index]['actions'][$key]['type'] = $action['type']->toArray();
+		}
+	}
   return civicrm_api3_create_success($returnValues, $params, 'FormProcessor', 'Get');
 }
 
diff --git a/api/v3/FormProcessorAction/Create.php b/api/v3/FormProcessorAction/Create.php
index 44230e39874fa4617d2df19a3fd590eb2a89520c..17abf812afcdc8e146e4af9931b18c85d8131211 100644
--- a/api/v3/FormProcessorAction/Create.php
+++ b/api/v3/FormProcessorAction/Create.php
@@ -42,6 +42,11 @@ function _civicrm_api3_form_processor_action_create_spec(&$spec) {
 		'type' => CRM_Utils_Type::T_TEXT,
 		'api_required' => false
 	);
+	$spec['mapping'] = array(
+		'title' => E::ts('Mapping'),
+		'type' => CRM_Utils_Type::T_TEXT,
+		'api_required' => false
+	);
 }
 
 /**
diff --git a/sql/create_civicrm_form_processor.sql b/sql/create_civicrm_form_processor.sql
index f9550018edccea6bb38a07ea3f26d35e5a9994dc..97ee8565151d128ed1a912fb77bf7018b5bdc9af 100644
--- a/sql/create_civicrm_form_processor.sql
+++ b/sql/create_civicrm_form_processor.sql
@@ -31,5 +31,6 @@ CREATE TABLE IF NOT EXISTS `civicrm_form_processor_action` (
   `title` VARCHAR(80) NOT NULL,
   `type` VARCHAR(80) NOT NULL,
   `configuration` TEXT NULL,
+  `mapping` TEXT NULL,
   PRIMARY KEY (`id`)
 ) ENGINE = InnoDB;