diff --git a/CRM/FormProcessor/BAO/FormProcessorInstance.php b/CRM/FormProcessor/BAO/FormProcessorInstance.php
index 1e9ddb2cfb009c1ecd1fb5205572379d0c046b65..22a0358cafca46dcfedd1c8be6717833b52f2f82 100644
--- a/CRM/FormProcessor/BAO/FormProcessorInstance.php
+++ b/CRM/FormProcessor/BAO/FormProcessorInstance.php
@@ -31,6 +31,24 @@
 			$row['inputs'] = array_values(CRM_FormProcessor_BAO_FormProcessorInput::getValues(array('form_processor_instance_id' => $formProcessorInstance->id)));
 			$row['actions'] = array_values(CRM_FormProcessor_BAO_FormProcessorAction::getValues(array('form_processor_instance_id' => $formProcessorInstance->id)));
 			
+			$handler = \Civi::service('form_processor_output_handler_factory')->getHandlerByName($row['output_handler']);
+			if ($handler) {
+				$configuration = $handler->getDefaultConfiguration();
+				if (isset($row['output_handler_configuration']) && is_string($row['output_handler_configuration'])) {
+					$row['output_handler_configuration'] = json_decode($row['output_handler_configuration'], true);
+				}
+				if (empty($row['output_handler_configuration']) || !is_array($row['output_handler_configuration'])) {
+					$row['output_handler_configuration'] = array();
+				}
+				foreach($row['output_handler_configuration'] as $name => $value) {
+					$configuration->set($name, $value);
+				}
+				$handler->setConfiguration($configuration);
+				
+				$row['output_handler'] = $handler;
+			}
+			
+			
       $result[$row['id']] = $row;
     }
     return $result;
@@ -70,6 +88,9 @@
         $formProcessorInstance->name = CRM_FormProcessor_BAO_FormProcessorInstance::buildNameFromLabel($formProcessorInstance->title);
       }
     }
+		if (is_array($formProcessorInstance->output_handler_configuration)) {
+			$formProcessorInstance->output_handler_configuration = json_encode($formProcessorInstance->output_handler_configuration);
+		}
     $formProcessorInstance->save();
     self::storeValues($formProcessorInstance, $result);
 
diff --git a/CRM/FormProcessor/DAO/FormProcessorInstance.php b/CRM/FormProcessor/DAO/FormProcessorInstance.php
index 1df1a4fc1f0cee022c5faf60c6a1e0d7100571c5..469d44019270ee292903ea3a3f0765c2e78ce013 100644
--- a/CRM/FormProcessor/DAO/FormProcessorInstance.php
+++ b/CRM/FormProcessor/DAO/FormProcessorInstance.php
@@ -47,6 +47,7 @@ class CRM_FormProcessor_DAO_FormProcessorInstance extends CRM_Core_DAO {
           'title' => E::ts('Title'),
           'type' => CRM_Utils_Type::T_STRING,
           'maxlength' => 128,
+          'required' => true
         ),
         'is_active' => array(
           'name' => 'is_active',
@@ -58,6 +59,18 @@ class CRM_FormProcessor_DAO_FormProcessorInstance extends CRM_Core_DAO {
           'title' => E::ts('Description'),
           'type' => CRM_Utils_Type::T_STRING,
         ),
+        'output_handler' => array(
+          'name' => 'output_handler',
+          'title' => E::ts('Output handler'),
+          'type' => CRM_Utils_Type::T_STRING,
+          'maxlength' => 88,
+          'required' => true,
+        ) ,
+        'output_handler_configuration' => array(
+        	'name' => 'output_handler_configuration',
+          'title' => E::ts('Output handler Configuration'),
+          'type' => CRM_Utils_Type::T_TEXT,
+				),
         'created_date' => array(
           'name' => 'created_date',
           'type' => CRM_Utils_Type::T_DATE
@@ -95,6 +108,8 @@ class CRM_FormProcessor_DAO_FormProcessorInstance extends CRM_Core_DAO {
         'label' => 'label',
         'is_active' => 'is_active',
         'description' => 'description',
+        'output_handler' => 'outpunt_handler',
+        'output_handler_configuration' => 'output_handler_configuration',
         'created_date' => 'created_date',
         'created_user_id' => 'created_user_id',
         'modified_date' => 'modified_date',
diff --git a/Civi/FormProcessor/API/Provider.php b/Civi/FormProcessor/API/Provider.php
index fe50e25dd1f731a003a49273e50b7fabaf23da58..e2e364f2091c35444ec911e264ec4593c22df7b8 100644
--- a/Civi/FormProcessor/API/Provider.php
+++ b/Civi/FormProcessor/API/Provider.php
@@ -10,6 +10,7 @@
  use Civi\API\Event\RespondEvent;
  use Civi\API\Events; 
  use Civi\API\Provider\ProviderInterface as API_ProviderInterface;
+ use Civi\FormProcessor\DataBag;
  use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 
 /**
@@ -103,7 +104,7 @@
    */
   public function invoke($apiRequest) {
   	$actionProvider = form_processor_get_action_provider();
-		$parameterBag = $actionProvider->createParameterBag();
+		$dataBag = new DataBag();
 			
   	$params = $apiRequest['params'];
   	  	
@@ -117,6 +118,9 @@
 		
 		// Validate the parameters.
 		foreach($formProcessor['inputs'] as $input) {
+			$objInput = new \CRM_FormProcessor_BAO_FormProcessorInput();
+			$objInput->copyValues($input);
+			
 			if ($input['is_required'] && !isset($params[$input['name']])) {
 				throw new \API_Exception('Parameter '.$input['name'].' is required');
 			}
@@ -129,24 +133,25 @@
 					throw new \API_Exception($validator['validator']->getInvalidMessage().' (Parameter '.$input['name'].')');
 				}
 			}
-			$parameterBag->setParameter('input.'.$input['name'], $params[$input['name']]);	
+			
+			$dataBag->setInputData($objInput, $params[$objInput->name]);
 		}
 		
 		// Execute the actions
 		$actionParams = array();
-		$output = array();
 		foreach($formProcessor['actions'] as $action) {
+			$objAction = new \CRM_FormProcessor_BAO_FormProcessorAction();
+			$objAction->copyValues($action);
+			
 			// Create a parameter bag for the action
+			$parameterBag = $dataBag->convertToActionProviderParameterBag($actionProvider);
 			$mappedParameterBag = $actionProvider->createdMappedParameterBag($parameterBag, $action['mapping']);
 			$outputBag = $action['type']->execute($mappedParameterBag);
-			foreach($outputBag as $field => $value) {
-				$outputParameterName = 'action.'.$action['id'].'.'.$field;
-				$parameterBag->setParameter($outputParameterName, $value);
-				$output[$action['title']][$field] = $value;
-			}
+			// Add the output of the action to the data bag of this action.
+			$dataBag->setActionDataFromActionProviderParameterBag($objAction, $outputBag);
 		}
-
-		return $output;
+		
+		return $formProcessor['output_handler']->handle($dataBag);
   }
 
   /**
diff --git a/Civi/FormProcessor/Config/Specification.php b/Civi/FormProcessor/Config/Specification.php
index 914af05c61fd12b630dfedabc7e59a16b5172e80..989b33bc7532574c363e7d0d77f6ca8a9f8b95d5 100644
--- a/Civi/FormProcessor/Config/Specification.php
+++ b/Civi/FormProcessor/Config/Specification.php
@@ -2,7 +2,9 @@
 
 namespace Civi\FormProcessor\Config;
 
-class Specification {
+use Civi\FormProcessor\Config\SpecificationInterface;
+
+class Specification implements SpecificationInterface {
 	
 	 /**
    * @var mixed
@@ -45,7 +47,7 @@ class Specification {
    * @param $name
    * @param $dataType
    */
-  public function __construct($name, $dataType = 'String', $title='', $required = false, $defaultValue = null, $fkEntity = null, $options = array(), $multiple = false, $description) {
+  public function __construct($name, $dataType = 'String', $title='', $required = false, $defaultValue = null, $fkEntity = null, $options = array(), $multiple = false, $description='') {
     $this->setName($name);
     $this->setDataType($dataType);
 		$this->setTitle($title);
@@ -57,6 +59,33 @@ class Specification {
 		$this->setDescription($description);
   }
 	
+	/**
+	 * Returns the type of specifcation
+	 * 
+	 * @return string
+	 */
+	public function getType() {
+		return 'specification';
+	}
+	
+	/**
+	 * Validates the given value
+	 * 
+	 * @param mixed $value
+	 * @return bool
+	 */
+	public function validateValue($value) {
+		if (isset($value)) {
+			// Check the type
+			if (!\CRM_Utils_Type::validate($value, $this->getDataType(), false)) {
+				return false;
+			}
+		} elseif ($this->isRequired()) {
+			return false;
+		}
+		return true;
+	}
+	
   /**
    * @return mixed
    */
@@ -243,6 +272,7 @@ class Specification {
       $key = strtolower(preg_replace('/(?=[A-Z])/', '_$0', $key));
       $ret[$key] = $val;
     }
+		$ret['type'] = $this->getType();
     return $ret;
   }
 	
diff --git a/Civi/FormProcessor/Config/SpecificationBag.php b/Civi/FormProcessor/Config/SpecificationBag.php
index 4f1e057e2a1dfdbb4ea55ddafebe1b0c02e9b4a5..c97b8b716b1eae02a4ca5df495bfbf375304ff6c 100644
--- a/Civi/FormProcessor/Config/SpecificationBag.php
+++ b/Civi/FormProcessor/Config/SpecificationBag.php
@@ -2,16 +2,30 @@
 
 namespace Civi\FormProcessor\Config;
 
+use Civi\FormProcessor\Config\SpecificationInterface;
+use Civi\FormProcessor\Config\ConfigurationBag;
+
 class SpecificationBag implements \IteratorAggregate  {
 	
 	protected $parameterSpecifications = array();
 	
+	/**
+	 * @param array <SpecificationInterface>
+	 */
 	public function __construct($specifcations = array()) {
 		foreach($specifcations as $spec) {
 			$this->parameterSpecifications[$spec->getName()] = $spec;
 		}
 	}
 	
+	public function getDefaultConfiguration() {
+		$default = new ConfigurationBag();
+		foreach($this->parameterSpecifications as $spec) {
+			$default->set($spec->getName(), $spec->getDefaultValue());
+		}	
+		return $default;
+	}
+	
 	/**
 	 * Validates the configuration.
 	 * 
@@ -23,12 +37,7 @@ class SpecificationBag implements \IteratorAggregate  {
 		foreach($specification as $spec) {
 			// First check whether the value is present and should be present.
 			$value = $configuration->get($spec->getName());
-			if (isset($value)) {
-				// Check the type
-				if (!\CRM_Utils_Type::validate($value, $spec->getDataType(), false)) {
-					return false;
-				}
-			} elseif ($spec->isRequired()) {
+			if (!$spec->validateValue($value)) {
 				return false;
 			}
 		}
@@ -36,21 +45,21 @@ class SpecificationBag implements \IteratorAggregate  {
 	}
 	
 	/**
-	 * @param Specification $specification
+	 * @param SpecificationInterface $specification
 	 *   The specification object.
 	 * @return SpecificationBag
 	 */
-	public function addSpecification(Specification $specification) {
+	public function addSpecification(SpecificationInterface $specification) {
 		$this->parameterSpecifications[$specification->getName()] = $specification;
 		return $this;
 	}
 	
 	/**
-	 * @param Specification $specification
+	 * @param SpecificationInterface $specification
 	 *   The specification object.
 	 * @return SpecificationBag
 	 */
-	public function removeSpecification(Specification $specification) {
+	public function removeSpecification(SpecificationInterface $specification) {
 		foreach($this->parameterSpecifications as $key => $spec) {
 			if ($spec == $specification) {
 				unset($this->parameterSpecifications[$key]);
@@ -76,7 +85,7 @@ class SpecificationBag implements \IteratorAggregate  {
 	/**
 	 * @param string $name
 	 *   The name of the parameter.
-	 * @return Specification|null
+	 * @return SpecificationInterface|null
 	 */
 	public function getSpecificationByName($name) {
 		foreach($this->parameterSpecifications as $key => $spec) {
@@ -98,9 +107,11 @@ class SpecificationBag implements \IteratorAggregate  {
 	 */
 	public function toArray() {
 		$return = array();
+		$return['parameter_specifications'] = array();
 		foreach($this->parameterSpecifications as $spec) {
-			$return[] = $spec->toArray();
+			$return['parameter_specifications'][] = $spec->toArray();
 		}
+		$return['default_configuration'] = $this->getDefaultConfiguration()->toArray();
 		return $return;
 	}
 	
diff --git a/Civi/FormProcessor/Config/SpecificationCollection.php b/Civi/FormProcessor/Config/SpecificationCollection.php
new file mode 100644
index 0000000000000000000000000000000000000000..ef9bc67be6095634e1c0e767faf7fccb53e4ea28
--- /dev/null
+++ b/Civi/FormProcessor/Config/SpecificationCollection.php
@@ -0,0 +1,223 @@
+<?php
+
+namespace Civi\FormProcessor\Config;
+
+use Civi\FormProcessor\Config\ConfigurationBag;
+use Civi\FormProcessor\Config\SpecificationBag;
+use Civi\FormProcessor\Config\SpecificationInterface;
+
+class SpecificationCollection implements SpecificationInterface {
+	
+	/**
+	 * @var SpecificationBag
+	 */
+	protected $specificationBag;
+	
+	/**
+	 * @var false|int
+	 */
+	protected $min = false;
+	
+	/**
+	 * @var false|int
+	 */
+	protected $max = false;
+	
+	/**
+   * @var string
+   */
+  protected $name;
+  /**
+   * @var string
+   */
+  protected $title;
+  /**
+   * @var string
+   */
+  protected $description;
+	
+	  /**
+   * @param $name
+   * @param $dataType
+   */
+  public function __construct($name, $title,  SpecificationBag $specificationBag, $min=false, $max=false, $description='') {
+    $this->setName($name);
+		$this->setTitle($title);
+		$this->setMin($min);
+		$this->setMax($max);
+		$this->specificationBag = $specificationBag;
+		$this->setDescription($description);
+  }
+	
+	/**
+	 * Returns the type of specifcation
+	 * 
+	 * @return string
+	 */
+	public function getType() {
+		return 'collection';
+	}
+	
+	/**
+	 * Validates the given value
+	 * 
+	 * @param mixed $value
+	 * @return bool
+	 */
+	public function validateValue($collection) {
+		if (!is_array($collection)) {
+			return false;
+		}
+		$count = count($collection);
+		if ($this->min !== false && $count < $this->min) {
+			return false;
+		}
+		if ($this->max !== false && $count > $this->max) {
+			return false;
+		}
+		foreach($collection as $value) {
+			if ($value instanceof ConfigurationBag) {
+				$configuration = $value;
+			} elseif (is_array($value)) {
+				$configuration = new ConfigurationBag();
+				foreach($value as $k => $v) {
+					$configuration->set($k, $v);
+				}
+			} else {
+				return false; // invalid value
+			}
+			if (!SpecificationBag::validate($configuration, $this->specificationBag)) {
+				return false;
+			}
+		}
+	}
+	
+	/**
+	 * Returns the default value
+	 * 
+	 * @return mixed
+	 */
+	public function getDefaultValue() {
+		$defaultValues = array();	
+		if ($this->min > 0) {
+			$defaultValue = new ConfigurationBag;
+			foreach($this->specificationBag as $spec) {
+				$defaultValue->setParameter($spec->getName(), $spec->getDefaultValue());
+			}
+			for($i=0; $i < $this->min; $i++) {
+				$defaultValues[] = $defaultValue;
+			}
+		}
+		return $defaultValues;
+	}
+	
+  /**
+   * @return string
+   */
+  public function getName() {
+    return $this->name;
+  }
+	
+  /**
+   * @param string $name
+   *
+   * @return $this
+   */
+  public function setName($name) {
+    $this->name = $name;
+    return $this;
+  }
+	
+  /**
+   * @return string
+   */
+  public function getTitle() {
+    return $this->title;
+  }
+	
+  /**
+   * @param string $title
+   *
+   * @return $this
+   */
+  public function setTitle($title) {
+    $this->title = $title;
+    return $this;
+  }
+	
+  /**
+   * @return string
+   */
+  public function getDescription() {
+    return $this->description;
+  }
+	
+  /**
+   * @param string $description
+   *
+   * @return $this
+   */
+  public function setDescription($description) {
+    $this->description = $description;
+    return $this;
+  }
+	
+	/**
+	 * Returns the minimum count for the collection. False if not set.
+	 * 
+	 * @return false|int
+	 */
+	public function getMin() {
+		return $this->min;
+	}
+	
+	/**
+	 * Sets the minimum count for the collection. False if not set.
+	 * 
+	 * @param false|int
+	 * @return SpecificationCollection
+	 */
+	public function setMin($min) {
+		$this->min = $min;
+		return $this;
+	}
+	
+	/**
+	 * Returns the maximum count for the collection. False if not set.
+	 * 
+	 * @return false|int
+	 */
+	public function getMax() {
+		return $this->max;
+	}
+	
+	/**
+	 * Sets the maximum count for the collection. False if not set.
+	 * 
+	 * @param false|int
+	 * @return SpecificationCollection
+	 */
+	public function setMax($max) {
+		$this->max = $max;
+		return $this;
+	}
+	
+	/**
+	 * Converts the object to an array.
+	 * 
+	 * @return array
+	 */
+  public function toArray() {
+    return array(
+    	'specification_bag' => $this->specificationBag->toArray(),
+    	'type' => $this->getType(),
+    	'name' => $this->getName(),
+    	'title' => $this->getTitle(),
+    	'description' => $this->getDescription(),
+    	'min' => $this->getMin(),
+    	'max' => $this->getMax(),
+    	'default_value' => $this->getDefaultValue(),
+		);
+  }
+	
+}
diff --git a/Civi/FormProcessor/Config/SpecificationFields.php b/Civi/FormProcessor/Config/SpecificationFields.php
new file mode 100644
index 0000000000000000000000000000000000000000..69fe056dd7add59f1dc303b481023c723ecdff44
--- /dev/null
+++ b/Civi/FormProcessor/Config/SpecificationFields.php
@@ -0,0 +1,170 @@
+<?php
+
+namespace Civi\FormProcessor\Config;
+
+use Civi\FormProcessor\Config\ConfigurationBag;
+use Civi\FormProcessor\Config\SpecificationBag;
+use Civi\FormProcessor\Config\SpecificationInterface;
+
+class SpecificationFields implements SpecificationInterface {
+	
+	/**
+   * @var string
+   */
+  protected $name;
+  /**
+   * @var string
+   */
+  protected $title;
+  /**
+   * @var string
+   */
+  protected $description;
+	
+	/**
+   * @var bool
+   */
+  protected $required = FALSE;
+	
+	/**
+	 * The key is the name of the field and the value the label
+	 * 
+	 * @var array
+	 */
+	protected $fields = array();
+	
+	/**
+   * @param string $name
+   * @param string $title, 
+	 * @param bool
+	 * @param array
+	 * @param string
+   */
+  public function __construct($name, $title, $required=false, $fields=array(), $description='') {
+    $this->setName($name);
+		$this->setTitle($title);
+		$this->fields = $fields;
+		$this->setDescription($description);
+		$this->setRequired($required);
+  }
+	
+	
+	public function getType() {
+		return 'fields';
+	}
+	
+	/**
+   * @return bool
+   */
+  public function isRequired() {
+    return $this->required;
+  }
+	
+  /**
+   * @param bool $required
+   *
+   * @return Field
+   */
+  public function setRequired($required) {
+    $this->required = $required;
+    return $this;
+  }
+	
+	/**
+   * @return string
+   */
+  public function getName() {
+    return $this->name;
+  }
+	
+  /**
+   * @param string $name
+   *
+   * @return $this
+   */
+  public function setName($name) {
+    $this->name = $name;
+    return $this;
+  }
+	
+  /**
+   * @return string
+   */
+  public function getTitle() {
+    return $this->title;
+  }
+	
+  /**
+   * @param string $title
+   *
+   * @return $this
+   */
+  public function setTitle($title) {
+    $this->title = $title;
+    return $this;
+  }
+	
+  /**
+   * @return string
+   */
+  public function getDescription() {
+    return $this->description;
+  }
+	
+  /**
+   * @param string $description
+   *
+   * @return $this
+   */
+  public function setDescription($description) {
+    $this->description = $description;
+    return $this;
+  }
+	
+	public function addField($name, $label) {
+		$this->field[$name] = $label;
+	}
+	
+	/**
+	 * @return array<Field>
+	 */
+	public function getFields() {
+		return $this->fields;
+	}
+	
+	/**
+	 * Validates the given value
+	 * 
+	 * @param mixed $value
+	 * @return bool
+	 */
+	public function validateValue($value) {
+		return true;
+	}
+	
+	/**
+	 * Returns the default value
+	 * 
+	 * @return mixed
+	 */
+	public function getDefaultValue() {
+		return null;
+	}
+	
+	/**
+	 * Converts the object to an array.
+	 * 
+	 * @return array
+	 */
+  public function toArray() {
+    return array(
+    	'type' => $this->getType(),
+    	'name' => $this->getName(),
+    	'title' => $this->getTitle(),
+    	'description' => $this->getDescription(),
+    	'fields' => $this->getFields(),
+    	'required' => $this->isRequired(),
+		);
+  }
+	
+}
\ No newline at end of file
diff --git a/Civi/FormProcessor/Config/SpecificationInterface.php b/Civi/FormProcessor/Config/SpecificationInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..858a9fd32c0a971b2da5b5d81bbbf982169145bb
--- /dev/null
+++ b/Civi/FormProcessor/Config/SpecificationInterface.php
@@ -0,0 +1,57 @@
+<?php
+
+namespace Civi\FormProcessor\Config;
+
+interface SpecificationInterface {
+	
+	/**
+	 * Returns the type of specifcation
+	 * 
+	 * @return string
+	 */
+	public function getType();
+	
+	/**
+	 * Returns the name of the specification
+	 * 
+	 * @return string
+	 */
+	public function getName();
+	
+	/**
+	 * Returns the title of the specification
+	 * 
+	 * @return string
+	 */
+	public function getTitle();
+	
+	/**
+	 * Returns the descripyion of the specification
+	 * 
+	 * @return string
+	 */
+	public function getDescription();
+	
+	/**
+	 * Validates the given value
+	 * 
+	 * @param mixed $value
+	 * @return bool
+	 */
+	public function validateValue($value);
+	
+	/**
+	 * Returns the default value
+	 * 
+	 * @return mixed
+	 */
+	public function getDefaultValue();
+	
+	/**
+	 * Returns the specification object as an array
+	 * 
+	 * @return array
+	 */
+	public function toArray();
+	
+}
diff --git a/Civi/FormProcessor/DataBag.php b/Civi/FormProcessor/DataBag.php
new file mode 100644
index 0000000000000000000000000000000000000000..6e34560c9b4fff2a38fe4b6e6cf8f0901e5f7bf7
--- /dev/null
+++ b/Civi/FormProcessor/DataBag.php
@@ -0,0 +1,134 @@
+<?php
+
+/**
+ * @author Jaap Jansma (CiviCooP) <jaap.jansma@civicoop.org>
+ * @license http://www.gnu.org/licenses/agpl-3.0.html
+ */
+
+namespace Civi\FormProcessor;
+
+class DataBag {
+	
+	private $inputs = array();
+	
+	private $actions = array();
+	
+	private $inputData = array();
+	
+	private $actionData = array();
+	/**
+	 * Sets the input data for a given input.
+	 * 
+	 * @param array $input
+	 * @return DataBag
+	 */
+	public function setInputData(\CRM_FormProcessor_BAO_FormProcessorInput $input, $value) {
+		$this->inputs[$input->id] = $input;
+		$this->inputData[$input->id] = $value;
+		return $this; 
+	}
+	
+	/** 
+	 * Retrieves the input data for a given input.
+	 * 
+	 * @param $input
+	 * @return string
+	 */
+	public function getInputData(\CRM_FormProcessor_BAO_FormProcessorInput $input) {
+		return $this->inputData[$input->id];
+	}
+	
+	/**
+	 * Returns an array with all the inputs.
+	 * 
+	 * @return array
+	 */
+	public function getAllInputs() {
+		return $this->inputs;
+	}
+	
+	/**
+	 * Sets the action data for a given action.
+	 * 
+	 * @param $action
+	 * @param string $field
+	 * @return DataBag
+	 */
+	public function setActionData(\CRM_FormProcessor_BAO_FormProcessorAction $action, $field, $value) {
+		$this->actions[$action->id] = $action;
+		$this->actionData[$action->id][$field] = $value;
+		return $this; 
+	}
+	
+	/** 
+	 * Retrieves all the action data for a given action.
+	 * 
+	 * @param $action
+	 * @return string
+	 */
+	public function getActionData(\CRM_FormProcessor_BAO_FormProcessorAction $action) {
+		return $this->actionData[$action->id];
+	}
+	
+	/**
+	 * Returns an array with all the actions.
+	 * 
+	 * @return array
+	 */
+	public function getAllActions() {
+		return $this->actions;
+	}
+	
+	/**
+	 * Sets the action data from an action provider parameter bag object.
+	 * 
+	 * @param $action
+	 * @param $parameterBag
+	 * @return DataBag
+	 */
+	public function setActionDataFromActionProviderParameterBag(\CRM_FormProcessor_BAO_FormProcessorAction $action, $parameterBag) {
+		$this->actions[$action->id] = $action;
+		foreach($parameterBag as $field => $value) {
+			$this->actionData[$action->id][$field] = $value;
+		}
+		return $this;
+	}
+	
+	/**
+	 * Returns the data by its alias. Returns null when the alias is not set
+	 * 
+	 * Example aliases:
+	 *   input.email
+	 *   action.3.contact_id
+	 * 
+	 * @param string
+	 * @return mixed|null 
+	 */
+	public function getDataByAlias($alias) {
+		$splitted_alias = explode(".", $alias);
+		if ($splitted_alias[0] == 'input') {
+			return $this->inputData[$splitted_alias[1]];
+		} elseif ($splitted_alias[0] == 'action') {
+			return $this->actionData[$splitted_alias[1]][$splitted_alias[2]];
+		}
+		return null;
+	}
+	
+	/**
+	 * Convert this data bag to the action provider parameter bag.
+	 */
+	public function convertToActionProviderParameterBag($actionProvider) {
+		$parameterBag = $actionProvider->createParameterBag();
+		foreach($this->inputs as $input) {
+			$parameterBag->setParameter('input.'.$input->name, $this->inputData[$input->id]);	
+		}
+		foreach($this->actions as $action) {
+			foreach($this->actionData[$action->id] as $field => $value) {
+				$outputParameterName = 'action.'.$action->id.'.'.$field;
+				$parameterBag->setParameter($outputParameterName, $value);	
+			}
+		}
+		return $parameterBag;
+	}
+	
+}
diff --git a/Civi/FormProcessor/OutputHandler/AbstractOutputHandler.php b/Civi/FormProcessor/OutputHandler/AbstractOutputHandler.php
new file mode 100644
index 0000000000000000000000000000000000000000..e8ae281b3a7111d16f3e54175cbea73b71a4940f
--- /dev/null
+++ b/Civi/FormProcessor/OutputHandler/AbstractOutputHandler.php
@@ -0,0 +1,112 @@
+<?php
+
+/**
+ * @author Jaap Jansma (CiviCooP) <jaap.jansma@civicoop.org>
+ * @license http://www.gnu.org/licenses/agpl-3.0.html
+ */
+ 
+ namespace Civi\FormProcessor\OutputHandler;
+ 
+ use \Civi\FormProcessor\Config\ConfigurationBag;
+ use \Civi\FormProcessor\Config\Specification;
+ use \Civi\FormProcessor\Config\SpecificationBag;
+ use \Civi\FormProcessor\OutputHandler\OutputHandlerInterface;
+ use \Civi\FormProcessor\DataBag;
+ 
+ abstract class AbstractOutputHandler implements OutputHandlerInterface {
+ 	
+	/**
+	 * @var ConfigurationBag
+	 */
+	protected $configuration;
+	
+	/**
+	 * @var ConfigurationBag
+	 */
+	protected $defaultConfiguration;
+	
+	/**
+	 * Get the configuration specification
+	 * 
+	 * @return SpecificationBag
+	 */
+	abstract public function getConfigurationSpecification();
+	
+	/**
+	 * Convert the action data to output data.
+	 * 
+	 * @param DataBag $dataBag
+	 * @return array
+	 */
+	abstract public function handle(DataBag $dataBag);
+	
+	/**
+	 * Returns the label of the output handler.
+	 * 
+	 * @return string
+	 */
+	abstract public function getLabel();
+	
+	public function __construct() {
+		$this->configuration = null;
+		$this->defaultConfiguration = null;
+	}
+	
+	/**
+	 * @return ConfigurationBag
+	 */
+	public function getConfiguration() {
+		if (!$this->configuration) {
+			$this->configuration = clone $this->getDefaultConfiguration();
+		}
+		return $this->configuration;
+	}
+	
+	/**
+	 * @return ConfigurationBag
+	 */
+	public function getDefaultConfiguration() {
+		if (!$this->defaultConfiguration) {
+			$this->defaultConfiguration = new ConfigurationBag();
+			foreach($this->getConfigurationSpecification() as $spec) {
+				$this->defaultConfiguration->set($spec->getName(), $spec->getDefaultValue());
+			}
+		}
+		return $this->defaultConfiguration;
+	}
+	
+	/**
+	 * @param ConfigurationBag $configuration
+	 */
+	public function setConfiguration(ConfigurationBag $configuration) {
+		$this->configuration = $configuration;
+		return $this;
+	}
+	
+	/**
+	 * Converts the handler to an array
+	 * 
+	 * @return array
+	 */
+	public function toArray() {
+		return array(
+			'name' => $this->getName(),
+			'label' => $this->getLabel(),
+			'configuration_spec' => $this->getConfigurationSpecification()->toArray(),
+			'configuration' => $this->getConfiguration()->toArray(),
+			'default_configuration' => $this->getDefaultConfiguration()->toArray(),
+		);
+	}
+	
+	/**
+	 * Returns the name of the output handler.
+	 * 
+	 * @return string
+	 */
+	public function getName() {
+		$reflect = new \ReflectionClass($this);
+		$className = $reflect->getShortName();
+		return $className;
+	}
+	
+ }
diff --git a/Civi/FormProcessor/OutputHandler/Factory.php b/Civi/FormProcessor/OutputHandler/Factory.php
new file mode 100644
index 0000000000000000000000000000000000000000..56208c29ded93870f3290978e611ee3e4c67c068
--- /dev/null
+++ b/Civi/FormProcessor/OutputHandler/Factory.php
@@ -0,0 +1,84 @@
+<?php
+
+/**
+ * @author Jaap Jansma (CiviCooP) <jaap.jansma@civicoop.org>
+ * @license http://www.gnu.org/licenses/agpl-3.0.html
+ */
+ 
+ namespace Civi\FormProcessor\OutputHandler;
+ 
+ use \Civi\FormProcessor\OutputHandler\OutputHandlerInterface;
+ use \Civi\FormProcessor\OutputHandler\OutputAllActionOutput;
+ use \Civi\FormProcessor\OutputHandler\FormatOutput;
+ 
+ class Factory {
+ 	
+	/**
+	 * @var array<OutputHandlerInterface>
+	 */
+	protected $handlers = array();
+	
+	/**
+	 * @var OutputHandlerInterface
+	 */
+	protected $defaultHandler;
+	
+	public function __construct() {
+		$this->defaultHandler = new OutputAllActionOutput();
+		$this->addHandler($this->defaultHandler);
+		$this->addHandler(new FormatOutput());
+	}
+	
+	/**
+	 * Returns the default output handler
+	 * 
+	 * @return OutputHandlerInterface
+	 */
+	public function getDefaultHandler() {
+		return $this->defaultHandler;
+	}
+	
+	/**
+	 * Add a handler
+	 * 
+	 * @param OutputHandlerInterface $handler
+	 */
+	public function addHandler(OutputHandlerInterface $handler) {
+		$this->handlers[$handler->getName()] = $handler;
+		return $this;
+	}
+	
+	/**
+	 * Return the handler
+	 * 
+	 * @param string $name
+	 * @return OutputHandlerInterface|null
+	 */
+	public function getHandlerByName($name) {
+		if (isset($this->handlers[$name])) {
+			return $this->handlers[$name];
+		}
+		return null;
+	}
+	
+	/**
+	 * @return array<OutputHandlerInterface>
+	 */
+	public function getHandlers() {
+		return $this->handlers;
+	}
+	
+	/**
+	 * Returns an array with the name and the array of the handler
+	 * 
+	 * @return array<array>
+	 */
+	public function getHandlersAsArray() {
+		$return = array();
+		foreach($this->handlers as $handler) {
+			$return[] = $handler->toArray();
+		}
+		return $return;
+	}
+	
+ }
diff --git a/Civi/FormProcessor/OutputHandler/FormatOutput.php b/Civi/FormProcessor/OutputHandler/FormatOutput.php
new file mode 100644
index 0000000000000000000000000000000000000000..2fc8f21c1e0fb478f21ed96b54b2376334a1a46c
--- /dev/null
+++ b/Civi/FormProcessor/OutputHandler/FormatOutput.php
@@ -0,0 +1,77 @@
+<?php
+
+/**
+ * @author Jaap Jansma (CiviCooP) <jaap.jansma@civicoop.org>
+ * @license http://www.gnu.org/licenses/agpl-3.0.html
+ */
+ 
+ namespace Civi\FormProcessor\OutputHandler;
+ 
+ use \Civi\FormProcessor\Config\ConfigurationBag;
+ use \Civi\FormProcessor\Config\Specification;
+ use \Civi\FormProcessor\Config\SpecificationBag;
+ use \Civi\FormProcessor\Config\SpecificationCollection;
+ use \Civi\FormProcessor\Config\SpecificationFields;
+ use \Civi\FormProcessor\OutputHandler\AbstractOutputHandler;
+ use \Civi\FormProcessor\DataBag;
+ 
+ use CRM_FormProcessor_ExtensionUtil as E;
+ 
+ class FormatOutput extends AbstractOutputHandler {
+ 	
+	/**
+	 * Get the configuration specification
+	 * 
+	 * @return SpecificationBag
+	 */
+	public function getConfigurationSpecification() {
+		return new SpecificationBag(array(
+			new SpecificationCollection(
+				'fields', 
+				E::ts('Output fields'), 
+				new SpecificationBag(array(
+					new SpecificationFields('field', E::ts('Field'), true),
+					new Specification('output_name', 'String', E::ts('Output name'), true),
+				))
+			)
+		));
+	}
+	
+	/**
+	 * Convert the action data to output data.
+	 * 
+	 * @param DataBag $dataBag
+	 * @return array
+	 */
+	public function handle(DataBag $dataBag) {
+		$output = array();	
+		$fields = $this->configuration->get('fields');
+		foreach($fields as $field) {
+			$output[$field['output_name']] = $dataBag->getDataByAlias($field['field']);
+		}
+		return $output;
+		
+		foreach($dataBag->getAllInputs() as $input) {
+			$output['input'][$input->name] = $dataBag->getInputData($input);
+		}
+		foreach($dataBag->getAllActions() as $action) {
+			$actionData['action'] = $action->title;
+			$actionData['output'] = $dataBag->getActionData($action);
+			if (!is_array($actionData['output'])) {
+				$actionData['output'] = array();	
+			} 
+			$output['action'][] = $actionData;
+		}
+		return $output;
+	}
+	
+	/**
+	 * Returns the label of the output handler.
+	 * 
+	 * @return string
+	 */
+	public function getLabel() {
+		return E::ts('Formal output');
+	}
+	
+ }
\ No newline at end of file
diff --git a/Civi/FormProcessor/OutputHandler/OutputAllActionOutput.php b/Civi/FormProcessor/OutputHandler/OutputAllActionOutput.php
new file mode 100644
index 0000000000000000000000000000000000000000..3899237d4f85aae928b3ce1603defad93f8da56b
--- /dev/null
+++ b/Civi/FormProcessor/OutputHandler/OutputAllActionOutput.php
@@ -0,0 +1,60 @@
+<?php
+
+/**
+ * @author Jaap Jansma (CiviCooP) <jaap.jansma@civicoop.org>
+ * @license http://www.gnu.org/licenses/agpl-3.0.html
+ */
+ 
+ namespace Civi\FormProcessor\OutputHandler;
+ 
+ use \Civi\FormProcessor\Config\ConfigurationBag;
+ use \Civi\FormProcessor\Config\Specification;
+ use \Civi\FormProcessor\Config\SpecificationBag;
+ use \Civi\FormProcessor\OutputHandler\AbstractOutputHandler;
+ use \Civi\FormProcessor\DataBag;
+ 
+ use CRM_FormProcessor_ExtensionUtil as E;
+ 
+ class OutputAllActionOutput extends AbstractOutputHandler {
+ 	
+	/**
+	 * Get the configuration specification
+	 * 
+	 * @return SpecificationBag
+	 */
+	public function getConfigurationSpecification() {
+		return new SpecificationBag();
+	}
+	
+	/**
+	 * Convert the action data to output data.
+	 * 
+	 * @param DataBag $dataBag
+	 * @return array
+	 */
+	public function handle(DataBag $dataBag) {
+		$output = array();
+		foreach($dataBag->getAllInputs() as $input) {
+			$output['input'][$input->name] = $dataBag->getInputData($input);
+		}
+		foreach($dataBag->getAllActions() as $action) {
+			$actionData['action'] = $action->title;
+			$actionData['output'] = $dataBag->getActionData($action);
+			if (!is_array($actionData['output'])) {
+				$actionData['output'] = array();	
+			} 
+			$output['action'][] = $actionData;
+		}
+		return $output;
+	}
+	
+	/**
+	 * Returns the label of the output handler.
+	 * 
+	 * @return string
+	 */
+	public function getLabel() {
+		return E::ts('Output all the output from all the actions');
+	}
+	
+ }
\ No newline at end of file
diff --git a/Civi/FormProcessor/OutputHandler/OutputHandlerInterface.php b/Civi/FormProcessor/OutputHandler/OutputHandlerInterface.php
new file mode 100644
index 0000000000000000000000000000000000000000..02d4f7f0d4a972000c803584b2e92852b7141400
--- /dev/null
+++ b/Civi/FormProcessor/OutputHandler/OutputHandlerInterface.php
@@ -0,0 +1,68 @@
+<?php
+
+/**
+ * @author Jaap Jansma (CiviCooP) <jaap.jansma@civicoop.org>
+ * @license http://www.gnu.org/licenses/agpl-3.0.html
+ */
+ 
+ namespace Civi\FormProcessor\OutputHandler;
+ 
+ use \Civi\FormProcessor\Config\ConfigurationBag;
+ use \Civi\FormProcessor\Config\Specification;
+ use \Civi\FormProcessor\Config\SpecificationBag;
+ use \Civi\FormProcessor\DataBag;
+ 
+ interface OutputHandlerInterface {
+ 	
+	/**
+	 * Get the configuration specification
+	 * 
+	 * @return SpecificationBag
+	 */
+	public function getConfigurationSpecification();
+	
+	/**
+	 * @return ConfigurationBag
+	 */
+	public function getConfiguration();
+	
+	/**
+	 * @return ConfigurationBag
+	 */
+	public function getDefaultConfiguration();
+	
+	/**
+	 * @param ConfigurationBag $configuration
+	 */
+	public function setConfiguration(ConfigurationBag $configuration);
+	
+	/**
+	 * Convert the action data to output data.
+	 * 
+	 * @param DataBag $dataBag
+	 * @return array
+	 */
+	public function handle(DataBag $dataBag);
+	
+	/**
+	 * Converts the handler to an array
+	 * 
+	 * @return array
+	 */
+	public function toArray();
+	
+	/**
+	 * Returns the name of the output handler.
+	 * 
+	 * @return string
+	 */
+	public function getName();
+	
+	/**
+	 * Returns the label of the output handler.
+	 * 
+	 * @return string
+	 */
+	public function getLabel();
+	
+ }
diff --git a/Civi/FormProcessor/Type/AbstractType.php b/Civi/FormProcessor/Type/AbstractType.php
index 2b771f2c726b63036f5c89c347974516fb7adc39..4f060056b0a4c8af522985e659ba31c3b8c978ff 100644
--- a/Civi/FormProcessor/Type/AbstractType.php
+++ b/Civi/FormProcessor/Type/AbstractType.php
@@ -128,6 +128,7 @@
 			'label' => $this->label,
 			'configuration_spec' => $this->getConfigurationSpecification()->toArray(),
 			'configuration' => $this->getConfiguration()->toArray(),
+			'default_configuration' => $this->getDefaultConfiguration()->toArray(),
 		);
 	}
 	
diff --git a/ang/form_processor.ang.php b/ang/form_processor.ang.php
index 520547d66c3c4130bca23087397e6219036819e3..e6dafb637323c0b70a758e75dc36b45e05de5215 100644
--- a/ang/form_processor.ang.php
+++ b/ang/form_processor.ang.php
@@ -35,6 +35,8 @@ return array (
   array (
   	'inputTypes' => \Civi::service('form_processor_type_factory')->getTypeLabels(),
   	'validators' => \Civi::service('form_processor_validation_factory')->getValidators(),
+  	'outputHandlers' => \Civi::service('form_processor_output_handler_factory')->getHandlersAsArray(),
+  	'defaultOutputHandler' => \Civi::service('form_processor_output_handler_factory')->getDefaultHandler()->toArray(),
   	'actionTypes' => $action_provider->getActions(),
   ),
 );
diff --git a/ang/form_processor/FormProcessorEditCtrl.html b/ang/form_processor/FormProcessorEditCtrl.html
index 0d81dbfba4886471f24b37f9617a2d8cf1c6cc6f..60f24a91c90408ff301bda3cfe841f67d0e2c463 100644
--- a/ang/form_processor/FormProcessorEditCtrl.html
+++ b/ang/form_processor/FormProcessorEditCtrl.html
@@ -18,6 +18,8 @@ Required vars: formProcessor
   <div ng-include="'~/form_processor/FormProcessorEditCtrl/InputTable.html'"></div>
   
   <div ng-include="'~/form_processor/FormProcessorEditCtrl/ActionTable.html'"></div>
+  
+  <div ng-include="'~/form_processor/FormProcessorEditCtrl/OutputHandler.html'"></div>
 
   <div class="crm-submit-buttons">
     <button crm-icon="fa-check" ng-click="save(false);" ng-disabled="editFormProcessorForm.$invalid || !isNameValid">
diff --git a/ang/form_processor/FormProcessorEditCtrl.js b/ang/form_processor/FormProcessorEditCtrl.js
index bb6aaa03b3ab6d686c059944ffbc7731437ba7a8..b19c0b33e61e2a0bf4128920bdeb20fda05b07d6 100644
--- a/ang/form_processor/FormProcessorEditCtrl.js
+++ b/ang/form_processor/FormProcessorEditCtrl.js
@@ -12,7 +12,9 @@
           		title: '',
           		is_active: '1',
           		inputs: [],
-          		actions: []
+          		actions: [],
+          		output_handler: false,
+          		output_handler_configuration: [],
         		};
           	return reqs;
           }
@@ -60,6 +62,11 @@
     }
     $scope.deletedActions = [];
     
+    $scope.outputHandlers = CRM.form_processor.outputHandlers;
+    if (!$scope.formProcessor.output_handler) {
+    	$scope.formProcessor.output_handler = CRM.form_processor.defaultOutputHandler;
+    }
+    
     $scope.$watch('formProcessor.name', function(newFormProcessorName, oldFrmProcessorName) {
     	// Watch for changes in the name field
       crmApi('FormProcessorInstance', 'validatename', {'name': newFormProcessorName,'id': $scope.formProcessor.id})
@@ -89,98 +96,100 @@
     	return (!name) || name.match(/^[a-z0-9_]+$/) ? true : false;
     };
     
-    $scope.save = function(goBack) {
+    $scope.save = function(goBack) {    	
+    	var output_handler = angular.copy($scope.formProcessor.output_handler);
+    	$scope.formProcessor.output_handler = output_handler.name;
+    	$scope.formProcessor.output_handler_configuration = output_handler.configuration;
       var result = crmApi('FormProcessorInstance', 'create', $scope.formProcessor, true);
       result.then(function(data) {
-        if (data.is_error === 0 || data.is_error == '0') {
-          $scope.formProcessor.id = data.id;  
-          
-          var apiCalls = [];
-          
-          angular.forEach($scope.deletedInputs, function(input, key) {
-          	if (input.id) {
-          		apiCalls.push(crmApi('FormProcessorInput', 'delete', {'id': input.id}, true));
-          	}
-          });
-          
-          angular.forEach($scope.formProcessor.inputs, function(input, key) {
-          	if (input.id < 1) {
-          		delete input.id;
-          	}
-          	var type = angular.copy(input.type);
-          	input.form_processor_instance_id = $scope.formProcessor.id;
-          	input.configuration = input.type.configuration; 
-          	input.type = input.type.name;
-          	apiCalls.push(crmApi('FormProcessorInput', 'create', input, true).then(function (input_result){
-        			input.id = input_result['id'];
-        			input.type = type;
-        			angular.forEach(input.validators, function(validator, validator_index){
-        				validator.form_processor_input_id = input.id;
-        				var validator_type = angular.copy(validator.validator);
-        				validator.validator = validator.validator.name;
-        				crmApi('FormProcessorInputValidation', 'create', validator).then(function (validator_result) {
-        					validator.validator = validator_type;
-        				});
-        			});
-        		}));
-          });
-          
-          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;
-          	}
-          	var action_type = angular.copy(action.type);
-          	action.form_processor_instance_id = $scope.formProcessor.id; 
-          	action.type = action.type.name;
-          	action.weight = actionWeight;
-          	apiCalls.push(crmApi('FormProcessorAction', 'create', action, true).then(function(action_result) {
-          		action.id = action_result.id;
-          		action.type = action_type;
-          		if (old_id < 0) {
-          			newActions[old_id] = action.id;          		
-          		}
-        		}));
-          	actionWeight++;
-          });
-          
-          // 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) {
-	       				var action_type = angular.copy(action.type);
-	       				action.type = action.type.name;
-	       				crmApi('FormProcessorAction', 'create', action, true).then(function(action_result) {
-	       					action.type = action_type;
-	       				});
-	       			}
-	       		});
-          });
-          
-          $scope.editFormProcessorForm.$setPristine();
-          
-          if (goBack) {
-          	window.location.href = '#/formprocessors';
-          }
+        $scope.formProcessor.id = data.id;
+        $scope.formProcessor.output_handler = output_handler;  
+        
+        var apiCalls = [];
+        
+        angular.forEach($scope.deletedInputs, function(input, key) {
+        	if (input.id) {
+        		apiCalls.push(crmApi('FormProcessorInput', 'delete', {'id': input.id}, true));
+        	}
+        });
+        
+        angular.forEach($scope.formProcessor.inputs, function(input, key) {
+        	if (input.id < 1) {
+        		delete input.id;
+        	}
+        	var type = angular.copy(input.type);
+        	input.form_processor_instance_id = $scope.formProcessor.id;
+        	input.configuration = input.type.configuration; 
+        	input.type = input.type.name;
+        	apiCalls.push(crmApi('FormProcessorInput', 'create', input, true).then(function (input_result){
+      			input.id = input_result['id'];
+      			input.type = type;
+      			angular.forEach(input.validators, function(validator, validator_index){
+      				validator.form_processor_input_id = input.id;
+      				var validator_type = angular.copy(validator.validator);
+      				validator.validator = validator.validator.name;
+      				crmApi('FormProcessorInputValidation', 'create', validator).then(function (validator_result) {
+      					validator.validator = validator_type;
+      				});
+      			});
+      		}));
+        });
+        
+        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;
+        	}
+        	var action_type = angular.copy(action.type);
+        	action.form_processor_instance_id = $scope.formProcessor.id; 
+        	action.type = action.type.name;
+        	action.weight = actionWeight;
+        	apiCalls.push(crmApi('FormProcessorAction', 'create', action, true).then(function(action_result) {
+        		action.id = action_result.id;
+        		action.type = action_type;
+        		if (old_id < 0) {
+        			newActions[old_id] = action.id;          		
+        		}
+      		}));
+        	actionWeight++;
+        });
+        
+        // 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) {
+       				var action_type = angular.copy(action.type);
+       				action.type = action.type.name;
+       				crmApi('FormProcessorAction', 'create', action, true).then(function(action_result) {
+       					action.type = action_type;
+       				});
+       			}
+       		});
+        });
+        
+        $scope.editFormProcessorForm.$setPristine();
+        
+        if (goBack) {
+        	window.location.href = '#/formprocessors';
         }
       });
     };
@@ -288,6 +297,28 @@
 				}
 			});
     };
+    
+    $scope.editOutputHandler = function editOutputHandler() {
+    	var options = CRM.utils.adjustDialogDefaults({
+        autoOpen: false,
+        width: '40%',
+        height: 'auto',
+        title: ts('Edit output handler')
+      });
+      
+      $scope.updateFields($scope.formProcessor);
+      var model = {
+      	formProcessor: $scope.formProcessor,
+      	outputHandler: $scope.formProcessor.output_handler,
+      	outputHandlers: $scope.outputHandlers
+      };
+      dialogService.open('OutputHandlerDialog', '~/form_processor/OutputHandlerDialogCtrl.html', model, options)
+      .then(function(data) {
+      	$scope.editFormProcessorForm.$setDirty();
+      	console.log(data);
+      	$scope.formProcessor.output_handler = data.outputHandler;
+			});
+    };
   
   	$scope.updateFields = function updateFields(formProcessor, selectedAction) {
   		formProcessor.fields = [];
diff --git a/ang/form_processor/FormProcessorEditCtrl/OutputHandler.html b/ang/form_processor/FormProcessorEditCtrl/OutputHandler.html
new file mode 100644
index 0000000000000000000000000000000000000000..e65c90a6a27362c78f135d5ce9792b650eaf5929
--- /dev/null
+++ b/ang/form_processor/FormProcessorEditCtrl/OutputHandler.html
@@ -0,0 +1,6 @@
+<div class="crm-block" ng-form="OutputHandlerForm" crm-ui-id-scope>
+	<h3>{{ts('Output Handler')}}: {{formProcessor.output_handler.label}}</h3>
+	<div><a crm-icon="fa-edit" class="crm-hover-button" ng-click="editOutputHandler()" title="{{ts('Change and configure output handler')}}">
+		{{ts('Change and configure output handler')}}
+	</a></div>
+</div>
\ No newline at end of file
diff --git a/ang/form_processor/InputDialogCtrl.html b/ang/form_processor/InputDialogCtrl.html
index 6ca5aef8bc80948d37758e34b94661c812fe6b13..51a16e1ee7df9e7fdb7b1e60a5e37e53caba3b69 100644
--- a/ang/form_processor/InputDialogCtrl.html
+++ b/ang/form_processor/InputDialogCtrl.html
@@ -54,7 +54,7 @@
 	        		ng-options="newValidator.label for newValidator in validators">
         		<option value="">{{ts('- Select validation -')}}</option>
       		</select>
-      		<button crm-icon="fa-check" ng-click="addValidator(newValidator)">{{ts('Add validation rule')}}</button>
+      		<button crm-icon="fa-plus" ng-click="addValidator(newValidator)">{{ts('Add validation rule')}}</button>
       </div>
      </div>
      
diff --git a/ang/form_processor/OutputHandlerDialogCtrl.html b/ang/form_processor/OutputHandlerDialogCtrl.html
new file mode 100644
index 0000000000000000000000000000000000000000..4c04bfba6204f9442dd57ca26e2abf1aabd6bec2
--- /dev/null
+++ b/ang/form_processor/OutputHandlerDialogCtrl.html
@@ -0,0 +1,28 @@
+<div ng-controller="OutputHandlerDialogCtrl" class="crm-block crm-form-block">
+  <div class="crm-block crm-form-block" ng-form="OutputHandlerForm" crm-ui-id-scope>
+    <div class="crm-section">
+    	<h2>{{ts('Output handler')}}</h2>
+    			<select
+	        		crm-ui-id="OutputHandlerForm.outputHandler"
+	        		name="type"
+	        		ui-jq="select2"
+	        		ui-options="{dropdownAutoWidth : true, allowClear: true}"
+	        		ng-model="outputHandler"
+	        		ng-options="handler.label for handler in outputHandlers">
+        		<option value="">{{ts('- Select output handler -')}}</option>
+      		</select>
+    </div>
+    <div class="crm-section">
+    	<crm-form-processor-specification-bag
+    		specification-bag="outputHandler.configuration_spec"
+    		configuration="outputHandler.configuration"
+    		fields="formProcessor.fields"
+    	>
+    	</crm-form-processor-specification-bag>
+    </div>
+  </div>
+  
+  <button crm-icon="fa-check" ng-click="saveClick()" ng-disabled="OutputHandlerForm.$invalid">{{ts('Save and close')}}</button>
+	<button crm-icon="fa-times" ng-click="cancelClick()">{{ts('Cancel')}}</button>
+  
+</div>
\ No newline at end of file
diff --git a/ang/form_processor/OutputHandlerDialogCtrl.js b/ang/form_processor/OutputHandlerDialogCtrl.js
new file mode 100644
index 0000000000000000000000000000000000000000..89b0568aecc1480b9a4c6bbb8a315c1ef9caee6c
--- /dev/null
+++ b/ang/form_processor/OutputHandlerDialogCtrl.js
@@ -0,0 +1,29 @@
+(function(angular, $, _) {
+
+  angular.module('form_processor').controller('OutputHandlerDialogCtrl', function InputDialogCtrl($scope, dialogService) {
+    $scope.ts = CRM.ts(null);
+    
+    $scope.outputHandler = angular.copy($scope.model.outputHandler);
+    $scope.outputHandlers = $scope.model.outputHandlers;
+    $scope.formProcessor = $scope.model.formProcessor;
+    
+    angular.forEach($scope.outputHandlers, function (outputHandler, key) {
+    	outputHandler.configuration = outputHandler.default_configuration;
+    	if (outputHandler.name == $scope.outputHandler.name) {
+  			outputHandler.configuration = angular.copy($scope.outputHandler.configuration);
+    		$scope.outputHandler = outputHandler;
+    	}
+    });
+    
+    $scope.saveClick = function() {
+    	$scope.model.outputHandler = $scope.outputHandler;
+    	dialogService.close('OutputHandlerDialog', $scope.model);
+    };
+		
+		$scope.cancelClick = function() {
+    	dialogService.cancel('OutputHandlerDialog');
+    };
+    
+  });
+
+})(angular, CRM.$, CRM._);
\ No newline at end of file
diff --git a/ang/form_processor/config/crmFormProcessorSpecification.html b/ang/form_processor/config/crmFormProcessorSpecification.html
new file mode 100644
index 0000000000000000000000000000000000000000..c6d813e3761347cc2eda569fb585fa08329d8172
--- /dev/null
+++ b/ang/form_processor/config/crmFormProcessorSpecification.html
@@ -0,0 +1,50 @@
+<div ng-if="specification.type == 'specification'">
+	<input
+			crm-ui-field="{name: 'specification.name', title: specification.title, required: specification.required}"
+      type="text"
+      name="{{specification.name}}"
+      ng-model="configuration[specification.name]"
+      class="big crm-form-text"
+      ng-required="specification.required"
+    />
+</div>
+<div ng-if="specification.type == 'fields'">
+	<select
+  	crm-ui-id="{name: 'specification.name', title: specification.title, required: specification.required}"
+    name="{{specification.name}}"
+    ui-jq="select2"
+    ui-options="{allowClear: true}"
+    ng-model="configuration[specification.name]"
+    ng-required="specification.required"
+    ng-options="field.name as field.label for field in fields">
+    <option value=""> - {{specification.title}} - </option>
+  </select>
+</div>
+<div ng-if="specification.type == 'collection'">
+		<table>
+			<thead>
+				<th ng-repeat="collection_spec in specification.specification_bag.parameter_specifications">
+					{{collection_spec.title}}
+				</th>
+				<th></th>
+			</thead>
+			<tbody>
+				<tr ng-repeat="collection_config in configuration[specification.name]" ng-class-even="'crm-entity even-row even'" ng-class-odd="'crm-entity odd-row odd'">
+					<td ng-repeat="collection_spec in specification.specification_bag.parameter_specifications">
+						<crm-form-processor-specification
+    					specification="collection_spec"
+    					configuration="collection_config"
+    					fields="fields"
+    				>
+    				</crm-form-processor-specification>
+					</td>
+					<td>
+						<a crm-icon="fa-trash" class="crm-hover-button" ng-click="removeItem(collection_config)" title="{{ts('Remove')}}">{{ts('Remove')}}</a>
+					</td>	
+				</tr>
+			</tbody>
+			<button crm-icon="fa-plus" ng-click="addItemToCollection(specification.specification_bag)">{{ts('Add item')}}</button>
+</table>
+</div>
+
+<div class="description" ng-if="specification.description" ng-bind-html="specification.description"></div>
\ No newline at end of file
diff --git a/ang/form_processor/config/crmFormProcessorSpecification.js b/ang/form_processor/config/crmFormProcessorSpecification.js
new file mode 100644
index 0000000000000000000000000000000000000000..09aeeaab9e26a00e1f3200d98daefc9c3e49da9d
--- /dev/null
+++ b/ang/form_processor/config/crmFormProcessorSpecification.js
@@ -0,0 +1,56 @@
+(function(angular, $, _) {
+	
+	angular.module('form_processor').directive('crmFormProcessorSpecification', function($compile) {
+	  return {
+	    restrict: 'E',
+	    transclude: true,
+	    scope: {
+	      specification: '=specification',
+	      fields: '=fields',
+	      configuration: '=configuration',
+	    },
+	    templateUrl: '~/form_processor/config/crmFormProcessorSpecification.html',
+	    // Code below is from: https://stackoverflow.com/a/19172067/3853493
+	    // And is taken from that site because we need recursion of this directive.
+	    compile: function(tElement, tAttr, transclude) {
+	    	//We are removing the contents/innerHTML from the element we are going to be applying the 
+        //directive to and saving it to adding it below to the $compile call as the template
+        var contents = tElement.contents().remove();
+        var compiledContents;
+        return function(scope, iElement, iAttr) {
+        	scope.ts = CRM.ts(null);
+
+        	scope.addItemToCollection = function addItemToCollection(specificationBag) {
+        		var item_config = angular.copy(specificationBag.default_configuration);
+        		scope.configuration[scope.specification.name].push(item_config);
+        	};
+        	
+        	scope.removeItem = function removeItem(item) {
+        		var index = scope.configuration[scope.specification.name].indexOf(item);
+    				if (index >= 0) {
+    					scope.configuration[scope.specification.name].splice(index, 1);
+    				}
+        	};
+        	
+        	
+        	if(!compiledContents) {
+        		//Get the link function with the contents frome top level template with 
+        		//the transclude
+						compiledContents = $compile(contents, transclude);
+					}
+          //Call the link function to link the given scope and
+          //a Clone Attach Function, http://docs.angularjs.org/api/ng.$compile :
+          // "Calling the linking function returns the element of the template. 
+          //    It is either the original element passed in, 
+          //    or the clone of the element if the cloneAttachFn is provided."
+          compiledContents(scope, function(clone, scope) {
+          	//Appending the cloned template to the instance element, "iElement", 
+            //on which the directive is to used.
+            iElement.append(clone); 
+          });
+        };
+      }
+	  };
+	});
+	
+})(angular, CRM.$, CRM._);
\ No newline at end of file
diff --git a/ang/form_processor/config/crmFormProcessorSpecificationBag.html b/ang/form_processor/config/crmFormProcessorSpecificationBag.html
new file mode 100644
index 0000000000000000000000000000000000000000..a2fe918d4ef48732bc07de8bee8e5446acc3c32a
--- /dev/null
+++ b/ang/form_processor/config/crmFormProcessorSpecificationBag.html
@@ -0,0 +1,9 @@
+<ng-repeat ng-repeat="spec in specificationBag.parameter_specifications">
+	<div class="crm-section">
+	<crm-form-processor-specification
+		specification="spec"
+		configuration="configuration"
+		fields="fields"
+  ></crm-form-processor-specification>
+  </div>
+</ng-repeat>
\ No newline at end of file
diff --git a/ang/form_processor/config/crmFormProcessorSpecificationBag.js b/ang/form_processor/config/crmFormProcessorSpecificationBag.js
new file mode 100644
index 0000000000000000000000000000000000000000..d8ee7e89057a89bd8da899eaab649a91a7ccc100
--- /dev/null
+++ b/ang/form_processor/config/crmFormProcessorSpecificationBag.js
@@ -0,0 +1,17 @@
+(function(angular, $, _) {
+	
+	angular.module('form_processor').directive('crmFormProcessorSpecificationBag', function() {
+	  return {
+	    restrict: 'E',
+	    scope: {
+	      specificationBag: '=specificationBag',
+	      fields: '=fields',
+	      configuration: '=configuration',
+	    },
+	    templateUrl: '~/form_processor/config/crmFormProcessorSpecificationBag.html',
+	    link: function($scope, element, attrs){
+	    }
+	  };
+	});
+	
+})(angular, CRM.$, CRM._);
\ No newline at end of file
diff --git a/ang/form_processor/crmFormProcessorOutputHandler/FormatActionOutput.html b/ang/form_processor/crmFormProcessorOutputHandler/FormatActionOutput.html
new file mode 100644
index 0000000000000000000000000000000000000000..4975abc4025341f505705d009568bfa14d014c20
--- /dev/null
+++ b/ang/form_processor/crmFormProcessorOutputHandler/FormatActionOutput.html
@@ -0,0 +1,40 @@
+<div class="crm-block crm-form-block" ng-form="FormatActionOutputForm" ng-controller="FormatActionOutputCtrl">
+	<h4>{{ts('Output Specification')}}</h4>
+		<select
+  		crm-ui-id="FormatActionOutputForm.field"
+  		name="type"
+  		ui-jq="select2"
+  		ui-options="{dropdownAutoWidth : true, allowClear: true}"
+  		ng-model="field"
+  		ng-options="field.label for field in fields"
+  		>
+		<option value="">{{ts('- Select field to add to the output -')}}</option>
+	</select>
+	<button crm-icon="fa-check" ng-click="addField(field)">{{ts('Add field to output')}}</button>
+	
+	<table>
+  <thead>
+	  <tr>
+	    <th>{{ts('Field')}}</th>
+	    <th>{{ts('Output name')}}</th>
+	    <th></th>
+	  </tr>
+  </thead>
+  <tbody>
+	  <tr ng-repeat="configuration_field in configuration " ng-class-even="'crm-entity even-row even'" ng-class-odd="'crm-entity odd-row odd'">
+	    <td>{{configuration_field.field.label}}</td>
+	    <td>
+	    	<input
+        type="text"
+        ng-model="configuration_field.output_name"
+        class="big crm-form-text"
+        required
+        autofocus
+        />
+    	</td>
+	    <td>
+	    </td>
+	  </tr>
+  </tbody>
+	
+</div>
\ No newline at end of file
diff --git a/ang/form_processor/crmFormProcessorOutputHandler/FormatActionOutputCtrl.js b/ang/form_processor/crmFormProcessorOutputHandler/FormatActionOutputCtrl.js
new file mode 100644
index 0000000000000000000000000000000000000000..6775e79e0176c8e2b15bca417d941c8578c37b77
--- /dev/null
+++ b/ang/form_processor/crmFormProcessorOutputHandler/FormatActionOutputCtrl.js
@@ -0,0 +1,22 @@
+(function(angular, $, _) {
+
+  angular.module('form_processor').controller('FormatActionOutputCtrl', function FormatActionOutputCtrl($scope) {
+    $scope.ts = CRM.ts(null);
+    
+    $scope.configuration = outputHandler.configuration;
+    
+    //$scope.watchCollection('configuration')
+    
+    $scope.addField = function(field) {
+    	var splitted_field = field.name.split('.');
+    	var output_name = splitted_field[splitted_field.length - 1];
+    	$scope.configuration.push({
+    		'field': field,
+    		'output_name': output_name
+    	});
+    };
+		
+    
+  });
+
+})(angular, CRM.$, CRM._);
diff --git a/ang/form_processor/crmFormProcessorOutputHandler/OutputAllActionOutput.html b/ang/form_processor/crmFormProcessorOutputHandler/OutputAllActionOutput.html
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/api/v3/FormProcessorInstance/Create.php b/api/v3/FormProcessorInstance/Create.php
index 2167e42b4b0879675b381c5d932a196a2bbf3825..d315b94d4de49a4b932778af15d49de8e7f5cd97 100644
--- a/api/v3/FormProcessorInstance/Create.php
+++ b/api/v3/FormProcessorInstance/Create.php
@@ -37,6 +37,16 @@ function _civicrm_api3_form_processor_instance_create_spec(&$spec) {
 		'type' => CRM_Utils_Type::T_TEXT,
 		'api.required' => true
 	);
+	$spec['output_handler'] = array(
+		'title' => E::ts('Output handler'),
+		'type' => CRM_Utils_Type::T_STRING,
+		'api.required' => true
+	);
+	$spec['output_handler_configuration'] = array(
+		'title' => E::ts('Output handler configuration'),
+		'type' => CRM_Utils_Type::T_TEXT,
+		'api.required' => false
+	);
 }
 
 /**
diff --git a/api/v3/FormProcessorInstance/Get.php b/api/v3/FormProcessorInstance/Get.php
index 2de109f2d2a09ef7dd8e70b05a574d1f9ff770f8..085b7b88bb2bc129fd97580e65a7f4d8857a4021 100644
--- a/api/v3/FormProcessorInstance/Get.php
+++ b/api/v3/FormProcessorInstance/Get.php
@@ -11,15 +11,21 @@
 function civicrm_api3_form_processor_instance_get($params) {
   $returnValues = CRM_FormProcessor_BAO_FormProcessorInstance::getValues($params);
 	foreach($returnValues as $index => $formProcessor) {
+		// Convert inputs to arrays	
 		foreach($formProcessor['inputs'] as $key => $input) {
 			$returnValues[$index]['inputs'][$key]['type'] = $input['type']->toArray();
 			foreach($input['validators'] as $validator_key => $validator) {
 				$returnValues[$index]['inputs'][$key]['validators'][$validator_key]['validator'] = $validator['validator']->toArray();
 			}
 		}
+		
+		// Convert action object to arrays
 		foreach($formProcessor['actions'] as $key => $action) {
 			$returnValues[$index]['actions'][$key]['type'] = $action['type']->toArray();
 		}
+		
+		// Convert output handler object to array
+		$returnValues[$index]['output_handler'] = $returnValues[$index]['output_handler']->toArray();
 	}
   return civicrm_api3_create_success($returnValues, $params, 'FormProcessorInstance', 'Get');
 }
diff --git a/form_processor.php b/form_processor.php
index 13845c385fe2f41fca5afa2bcb286a8e2acfce34..ac5b817ed81aa36a8c200b53a138c7cc8190335a 100644
--- a/form_processor.php
+++ b/form_processor.php
@@ -14,6 +14,9 @@ use \Symfony\Component\DependencyInjection\Definition;
 function form_processor_civicrm_container(ContainerBuilder $container) {
 	// Register the TypeFactory
 	$container->setDefinition('form_processor_type_factory', new Definition('Civi\FormProcessor\Type\Factory'));
+	// Register the OutputHandlerFactory
+	$container->setDefinition('form_processor_output_handler_factory', new Definition('Civi\FormProcessor\OutputHandler\Factory'));
+	// Register the validationFactory
 	$validationFactoryDefinition = new Definition('Civi\FormProcessor\Validation\Factory');
 	$validationFactoryDefinition->setFactory(array('Civi\FormProcessor\Validation\Factory', 'singleton')); 
 	$container->setDefinition('form_processor_validation_factory', $validationFactoryDefinition);
diff --git a/sql/create_civicrm_form_processor.sql b/sql/create_civicrm_form_processor.sql
index 8f0b9be16165f6bd6d1cb6b9183cb5c99401fc83..14e7a430cf9e40750cad752f138b9e2e76752e54 100644
--- a/sql/create_civicrm_form_processor.sql
+++ b/sql/create_civicrm_form_processor.sql
@@ -4,6 +4,8 @@ CREATE TABLE IF NOT EXISTS `civicrm_form_processor_instance` (
   `title` VARCHAR(128) NULL,
   `is_active` TINYINT NULL DEFAULT 1,
   `description` TEXT NULL,
+  `output_handler` VARCHAR(88) NOT NULL,
+  `output_handler_configuration` TEXT NULL,
   `created_date` DATE NULL,
   `created_user_id` INT NULL,
   `modified_date` DATE NULL,