diff --git a/CRM/Dataprocessor/BAO/DataProcessor.php b/CRM/Dataprocessor/BAO/DataProcessor.php
index fe00305050b36959f0b53e569cef673fc82f913c..14e09256d3f667b93ebc83461ebf944b6b86db51 100644
--- a/CRM/Dataprocessor/BAO/DataProcessor.php
+++ b/CRM/Dataprocessor/BAO/DataProcessor.php
@@ -249,6 +249,16 @@ class CRM_Dataprocessor_BAO_DataProcessor extends CRM_Dataprocessor_DAO_DataProc
       }
     }
 
+    $filters = CRM_Dataprocessor_BAO_Filter::getValues(array('data_processor_id' => $this->id));
+    $filterHandlers = $dataProcessor->getAvailableFilterHandlers();
+    foreach($filters as $filter) {
+      if (isset($filterHandlers[$filter['type']])) {
+        $filterHandler = $filterHandlers[$filter['type']];
+        $filterHandler->initialize($filter['name'], $filter['title'], $filter['is_required'], $filter['configuration']);
+        $dataProcessor->addFilterHandler($filterHandler);
+      }
+    }
+
     $fields = CRM_Dataprocessor_BAO_Field::getValues(array('data_processor_id' => $this->id));
     $outputHandlers = $dataProcessor->getAvailableOutputHandlers();
     foreach($fields as $field) {
@@ -285,6 +295,29 @@ class CRM_Dataprocessor_BAO_DataProcessor extends CRM_Dataprocessor_DAO_DataProc
     return $dataProcessor->getAvailableOutputHandlers();
   }
 
+  public static function getAvailableFilterHandlers($data_processor_id) {
+    $dao = new CRM_Dataprocessor_BAO_DataProcessor();
+    $dao->id = $data_processor_id;
+    $dao->find(true);
+    $factory = dataprocessor_get_factory();
+    $dataProcessor = $factory->getDataProcessorTypeByName($dao->type);
+    $sources = CRM_Dataprocessor_BAO_Source::getValues(array('data_processor_id' => $dao->id));
+    foreach($sources as $sourceDao) {
+      $source = $factory->getDataSourceByName($sourceDao['type']);
+      $source->setSourceName($sourceDao['name']);
+      $source->setSourceTitle($sourceDao['title']);
+      $source->initialize($sourceDao['configuration']);
+      $join = null;
+      if ($sourceDao['join_type']) {
+        $join = $factory->getJoinByName($sourceDao['join_type']);
+        $join->initialize($sourceDao['join_configuration'], $dao->id);
+      }
+      $dataProcessor->addDataSource($source, $join);
+    }
+
+    return $dataProcessor->getAvailableFilterHandlers();
+  }
+
   public static function getAvailableAggregationFields($data_processor_id) {
     $availableAggregationFields = array();
     $factory = dataprocessor_get_factory();
@@ -373,6 +406,11 @@ class CRM_Dataprocessor_BAO_DataProcessor extends CRM_Dataprocessor_DAO_DataProc
       unset($dataProcessor['data_sources'][$i]['id']);
       unset($dataProcessor['data_sources'][$i]['data_processor_id']);
     }
+    $dataProcessor['filters'] = CRM_Dataprocessor_BAO_Filter::getValues(array('data_processor_id' => $id));
+    foreach($dataProcessor['filters'] as $i => $field) {
+      unset($dataProcessor['filters'][$i]['id']);
+      unset($dataProcessor['filters'][$i]['data_processor_id']);
+    }
     $dataProcessor['fields'] = CRM_Dataprocessor_BAO_Field::getValues(array('data_processor_id' => $id));
     foreach($dataProcessor['fields'] as $i => $field) {
       unset($dataProcessor['fields'][$i]['id']);
diff --git a/CRM/Dataprocessor/BAO/Filter.php b/CRM/Dataprocessor/BAO/Filter.php
new file mode 100644
index 0000000000000000000000000000000000000000..d649e5eb06d958b7a220b6e9ba3e7e7b8db5ee08
--- /dev/null
+++ b/CRM/Dataprocessor/BAO/Filter.php
@@ -0,0 +1,180 @@
+<?php
+/**
+ * @author Jaap Jansma <jaap.jansma@civicoop.org>
+ * @license AGPL-3.0
+ */
+
+class CRM_Dataprocessor_BAO_Filter extends CRM_Dataprocessor_DAO_Filter {
+
+  /**
+   * Function to get values
+   *
+   * @return array $result found rows with data
+   * @access public
+   * @static
+   */
+  public static function getValues($params) {
+    $factory = dataprocessor_get_factory();
+    $types = $factory->getDataSources();
+
+    $result = array();
+    $filter = new CRM_Dataprocessor_DAO_Filter();
+    if (!empty($params)) {
+      $filters = self::fields();
+      foreach ($params as $key => $value) {
+        if (isset($filters[$key])) {
+          $filter->$key = $value;
+        }
+      }
+    }
+    $filter->find();
+    while ($filter->fetch()) {
+      $row = array();
+      self::storeValues($filter, $row);
+
+      if (isset($types[$row['type']])) {
+        $row['type_name'] = $types[$row['type']];
+      } else {
+        $row['type_name'] = '';
+      }
+      if (!empty($row['configuration'])) {
+        $row['configuration'] = json_decode($row['configuration'], true);
+      } else {
+        $row['configuration'] = array();
+      }
+      if (!empty($row['join_configuration'])) {
+        $row['join_configuration'] = json_decode($row['join_configuration'], true);
+      } else {
+        $row['join_configuration'] = array();
+      }
+
+      $result[$row['id']] = $row;
+    }
+    return $result;
+  }
+
+  /**
+   * Function to add or update a DataProcessor
+   *
+   * @param array $params
+   * @return array $result
+   * @access public
+   * @throws Exception when params is empty
+   * @static
+   */
+  public static function add($params) {
+    $result = array();
+    if (empty($params)) {
+      throw new Exception('Params can not be empty when adding or updating a data processor filter');
+    }
+
+    if (!empty($params['id'])) {
+      CRM_Utils_Hook::pre('edit', 'DataProcessorFilter', $params['id'], $params);
+    }
+    else {
+      CRM_Utils_Hook::pre('create', 'DataProcessorFilter', NULL, $params);
+    }
+
+    $filter = new CRM_Dataprocessor_DAO_Filter();
+    $filters = self::fields();
+    foreach ($params as $key => $value) {
+      if (isset($filters[$key])) {
+        $filter->$key = $value;
+      }
+    }
+    if (isset($filter->configuration) && is_array($filter->configuration)) {
+      $filter->configuration = json_encode($filter->configuration);
+    }
+
+    $filter->save();
+    self::storeValues($filter, $result);
+
+    if (!empty($params['id'])) {
+      CRM_Utils_Hook::post('edit', 'DataProcessorFilter', $filter->id, $filter);
+    }
+    else {
+      CRM_Utils_Hook::post('create', 'DataProcessorFilter', $filter->id, $filter);
+    }
+
+    return $result;
+  }
+
+  /**
+   * Public function to generate name from title
+   *
+   * @param $label
+   * @return string
+   * @access public
+   * @static
+   */
+  public static function buildNameFromTitle($title) {
+    return preg_replace('@[^a-z0-9_]+@','_', strtolower($title));
+  }
+
+  /**
+   * Returns whether the name is valid or not
+   *
+   * @param string $name
+   * @param int $data_procssor_id,
+   * @param int $id optional
+   * @return bool
+   * @static
+   */
+  public static function isNameValid($name, $data_procssor_id, $id=null) {
+    $sql = "SELECT COUNT(*) FROM `civicrm_data_processor_filter` WHERE `name` = %1 AND `data_processor_id` = %2";
+    $params[1] = array($name, 'String');
+    $params[2] = array($data_procssor_id, 'Integer');
+    if ($id) {
+      $sql .= " AND `id` != %3";
+      $params[3] = array($id, 'Integer');
+    }
+    $count = CRM_Core_DAO::singleValueQuery($sql, $params);
+    return ($count > 0) ? false : true;
+  }
+
+  /**
+   * Function to delete a Data Processor Filter with id
+   *
+   * @param int $id
+   * @throws Exception when $id is empty
+   * @access public
+   * @static
+   */
+  public static function deleteWithId($id) {
+    if (empty($id)) {
+      throw new Exception('id can not be empty when attempting to delete a data processor filter');
+    }
+
+    CRM_Utils_Hook::pre('delete', 'DataProcessorFilter', $id, CRM_Core_DAO::$_nullArray);
+
+    $filter = new CRM_Dataprocessor_DAO_Filter();
+    $filter->id = $id;
+    $filter->delete();
+
+    CRM_Utils_Hook::post('delete', 'DataProcessorFilter', $id, CRM_Core_DAO::$_nullArray);
+
+    return;
+  }
+
+  /**
+   * Function to delete a Data Processor Filter with id
+   *
+   * @param int $id
+   * @throws Exception when $id is empty
+   * @access public
+   * @static
+   */
+  public static function deleteWithDataProcessorId($id) {
+    if (empty($id)) {
+      throw new Exception('id can not be empty when attempting to delete a data processor filter');
+    }
+
+    $filter = new CRM_Dataprocessor_DAO_Filter();
+    $filter->data_processor_id = $id;
+    $filter->find(FALSE);
+    while ($filter->fetch()) {
+      self::deleteWithId($filter->id);
+    }
+  }
+
+}
\ No newline at end of file
diff --git a/CRM/Dataprocessor/DAO/Filter.php b/CRM/Dataprocessor/DAO/Filter.php
new file mode 100644
index 0000000000000000000000000000000000000000..6be51fceaff8de35076466a95625863e8c83cf82
--- /dev/null
+++ b/CRM/Dataprocessor/DAO/Filter.php
@@ -0,0 +1,102 @@
+<?php
+
+use CRM_Dataprocessor_ExtensionUtil as E;
+
+/**
+ * @author Jaap Jansma (CiviCooP) <jaap.jansma@civicoop.org>
+ * @license http://www.gnu.org/licenses/agpl-3.0.html
+ */
+class CRM_Dataprocessor_DAO_Filter extends CRM_Core_DAO {
+  /**
+   * static instance to hold the field values
+   *
+   * @var array
+   * @static
+   */
+  static $_fields = null;
+  static $_export = null;
+  /**
+   * empty definition for virtual function
+   */
+  static function getTableName() {
+    return 'civicrm_data_processor_filter';
+  }
+  /**
+   * returns all the column names of this table
+   *
+   * @access public
+   * @return array
+   */
+  public static function &fields() {
+    if (!(self::$_fields)) {
+      self::$_fields = array(
+        'id' => array(
+          'name' => 'id',
+          'title' => E::ts('ID'),
+          'type' => CRM_Utils_Type::T_INT,
+          'required' => true
+        ) ,
+        'data_processor_id' => array(
+          'name' => 'data_processor_id',
+          'title' => E::ts('Data Processor ID'),
+          'type' => CRM_Utils_Type::T_INT,
+          'required' => true,
+          'FKApiName' => 'DataProcessor',
+        ),
+        'is_required' => array(
+          'name' => 'is_required',
+          'title' => E::ts('Is required'),
+          'type' => CRM_Utils_Type::T_INT,
+        ),
+        'type' => array(
+          'name' => 'type',
+          'title' => E::ts('Type'),
+          'type' => CRM_Utils_Type::T_STRING,
+          'maxlength' => 80,
+          'required' => true,
+        ),
+        'name' => array(
+          'name' => 'name',
+          'title' => E::ts('Name'),
+          'type' => CRM_Utils_Type::T_STRING,
+          'maxlength' => 128,
+          'required' => true
+        ),
+        'title' => array(
+          'name' => 'title',
+          'title' => E::ts('Title'),
+          'type' => CRM_Utils_Type::T_STRING,
+          'maxlength' => 128,
+          'required' => true
+        ),
+        'configuration' => array(
+          'name' => 'configuration',
+          'title' => E::ts('Configuration'),
+          'type' => CRM_Utils_Type::T_TEXT,
+        ),
+      );
+    }
+    return self::$_fields;
+  }
+  /**
+   * Returns an array containing, for each field, the array key used for that
+   * field in self::$_fields.
+   *
+   * @access public
+   * @return array
+   */
+  public static function &fieldKeys() {
+    if (!(self::$_fieldKeys)) {
+      self::$_fieldKeys = array(
+        'id' => 'id',
+        'data_processor_id' => 'data_processor_id',
+        'is_required' => 'is_required',
+        'type' => 'type',
+        'name' => 'name',
+        'title' => 'title',
+        'configuration' => 'configuration',
+      );
+    }
+    return self::$_fieldKeys;
+  }
+}
\ No newline at end of file
diff --git a/CRM/Dataprocessor/Form/DataProcessor.php b/CRM/Dataprocessor/Form/DataProcessor.php
index 66ee1bbe449eb86b168c650368d06a6ffb223c1f..2815ae7e62625441dc65e2725c7b7315c7c04d12 100644
--- a/CRM/Dataprocessor/Form/DataProcessor.php
+++ b/CRM/Dataprocessor/Form/DataProcessor.php
@@ -45,15 +45,18 @@ class CRM_Dataprocessor_Form_DataProcessor extends CRM_Core_Form {
     if ($this->dataProcessorId) {
       $this->addSources();
       $this->addFields();
+      $this->addFilters();
       $this->addAggregateFields();
       $this->assign('outputs', CRM_Dataprocessor_BAO_Output::getValues(array('data_processor_id' => $this->dataProcessorId)));
       $dataSourceAddUrl = CRM_Utils_System::url('civicrm/dataprocessor/form/source', 'reset=1&action=add&data_processor_id='.$this->dataProcessorId, TRUE);
       $addAggregateFieldUrl = CRM_Utils_System::url('civicrm/dataprocessor/form/aggregate_field', 'reset=1&action=add&id='.$this->dataProcessorId, TRUE);
       $addFieldUrl = CRM_Utils_System::url('civicrm/dataprocessor/form/field', 'reset=1&action=add&data_processor_id='.$this->dataProcessorId, TRUE);
+      $addFilterUrl = CRM_Utils_System::url('civicrm/dataprocessor/form/filter', 'reset=1&action=add&data_processor_id='.$this->dataProcessorId, TRUE);
       $outputAddUrl = CRM_Utils_System::url('civicrm/dataprocessor/form/output', 'reset=1&action=add&data_processor_id='.$this->dataProcessorId, TRUE);
       $this->assign('addDataSourceUrl', $dataSourceAddUrl);
       $this->assign('addAggregateFieldUrl', $addAggregateFieldUrl);
       $this->assign('addFieldUrl', $addFieldUrl);
+      $this->assign('addFilterUrl', $addFilterUrl);
       $this->assign('addOutputUrl', $outputAddUrl);
     }
   }
@@ -84,6 +87,15 @@ class CRM_Dataprocessor_Form_DataProcessor extends CRM_Core_Form {
     $this->assign('fields', $fields);
   }
 
+  protected function addFilters() {
+    $filters = CRM_Dataprocessor_BAO_Filter::getValues(array('data_processor_id' => $this->dataProcessorId));
+    foreach($filters as $idx => $filter) {
+      $filters[$idx]['is_required'] = $filter['is_required'] ? E::ts('Yes') : E::ts('No');
+      $filters[$idx]['configuration_link'] = '';
+    }
+    $this->assign('filters', $filters);
+  }
+
   protected function addAggregateFields() {
     $fields = array();
     $aggregationFields = CRM_Dataprocessor_BAO_DataProcessor::getAvailableAggregationFields($this->dataProcessorId);
diff --git a/CRM/Dataprocessor/Form/Filter.php b/CRM/Dataprocessor/Form/Filter.php
new file mode 100644
index 0000000000000000000000000000000000000000..4105eb38094d363c41d75548da8c96d03bb2b4dc
--- /dev/null
+++ b/CRM/Dataprocessor/Form/Filter.php
@@ -0,0 +1,165 @@
+<?php
+
+use CRM_Dataprocessor_ExtensionUtil as E;
+
+/**
+ * Form controller class
+ *
+ * @see https://wiki.civicrm.org/confluence/display/CRMDOC/QuickForm+Reference
+ */
+class CRM_Dataprocessor_Form_Filter extends CRM_Core_Form {
+
+  private $dataProcessorId;
+
+  private $id;
+
+  /**
+   * Function to perform processing before displaying form (overrides parent function)
+   *
+   * @access public
+   */
+  function preProcess() {
+    $session = CRM_Core_Session::singleton();
+    $this->dataProcessorId = CRM_Utils_Request::retrieve('data_processor_id', 'Integer');
+    $this->assign('data_processor_id', $this->dataProcessorId);
+
+    $this->id = CRM_Utils_Request::retrieve('id', 'Integer');
+    $this->assign('id', $this->id);
+
+    if ($this->id) {
+      $filter = CRM_Dataprocessor_BAO_Filter::getValues(array('id' => $this->id));
+      $this->assign('filter', $filter[$this->id]);
+    }
+
+    $title = E::ts('Data Processor Filter');
+    CRM_Utils_System::setTitle($title);
+
+    $url = CRM_Utils_System::url('civicrm/dataprocessor/form/edit', array('id' => $this->dataProcessorId, 'action' => 'update', 'reset' => 1));
+    $session->pushUserContext($url);
+  }
+
+  public function buildQuickForm() {
+    $this->add('hidden', 'data_processor_id');
+    $this->add('hidden', 'id');
+    if ($this->_action != CRM_Core_Action::DELETE) {
+      $this->add('text', 'name', E::ts('Name'), array('size' => CRM_Utils_Type::HUGE), FALSE);
+      $this->add('text', 'title', E::ts('Title'), array('size' => CRM_Utils_Type::HUGE), TRUE);
+
+      $filterHandlers = CRM_Dataprocessor_BAO_DataProcessor::getAvailableFilterHandlers($this->dataProcessorId);
+      $filterHandlersSelect = array(E::ts('- Select -'));
+      foreach($filterHandlers as $filterHandler) {
+        $filterHandlersSelect[$filterHandler->getName()] = $filterHandler->getTitle();
+      }
+
+      $this->add('select', 'type', E::ts('Select Filter'), $filterHandlersSelect, true, array('class' => 'crm-select2 crm-huge40'));
+
+      $this->add('checkbox', 'is_required', E::ts('Is required'));
+    }
+    if ($this->_action == CRM_Core_Action::ADD) {
+      $this->addButtons(array(
+        array('type' => 'next', 'name' => E::ts('Next'), 'isDefault' => TRUE,),
+        array('type' => 'cancel', 'name' => E::ts('Cancel'))));
+    } elseif ($this->_action == CRM_Core_Action::DELETE) {
+      $this->addButtons(array(
+        array('type' => 'next', 'name' => E::ts('Delete'), 'isDefault' => TRUE,),
+        array('type' => 'cancel', 'name' => E::ts('Cancel'))));
+    } else {
+      $this->addButtons(array(
+        array('type' => 'next', 'name' => E::ts('Save'), 'isDefault' => TRUE,),
+        array('type' => 'cancel', 'name' => E::ts('Cancel'))));
+    }
+    parent::buildQuickForm();
+  }
+
+  function setDefaultValues() {
+    $defaults = [];
+    $defaults['data_processor_id'] = $this->dataProcessorId;
+    $defaults['id'] = $this->id;
+
+    $filter = CRM_Dataprocessor_BAO_Filter::getValues(array('id' => $this->id));
+    if (isset($filter[$this->id]['type'])) {
+      $defaults['type'] = $filter[$this->id]['type'];
+    }
+    if (isset($filter[$this->id]['is_required'])) {
+      $defaults['is_required'] = $filter[$this->id]['is_required'];
+    }
+    if (isset($filter[$this->id]['title'])) {
+      $defaults['title'] = $filter[$this->id]['title'];
+    }
+    if (isset($filter[$this->id]['name'])) {
+      $defaults['name'] = $filter[$this->id]['name'];
+    }
+    return $defaults;
+  }
+
+  public function postProcess() {
+    $session = CRM_Core_Session::singleton();
+    $redirectUrl = $session->readUserContext();
+    if ($this->_action == CRM_Core_Action::DELETE) {
+      CRM_Dataprocessor_BAO_Filter::deleteWithId($this->id);
+      $session->setStatus(E::ts('Filter removed'), E::ts('Removed'), 'success');
+      CRM_Utils_System::redirect($redirectUrl);
+    }
+
+    $values = $this->exportValues();
+    if (!empty($values['name'])) {
+      $params['name'] = $values['name'];
+    } else {
+      $params['name'] = CRM_Dataprocessor_BAO_Filter::buildNameFromTitle($values['title']);
+    }
+    $params['title'] = $values['title'];
+    $params['type'] = $values['type'];
+    $params['is_required'] = $values['is_required'];
+    if ($this->dataProcessorId) {
+      $params['data_processor_id'] = $this->dataProcessorId;
+    }
+    if ($this->id) {
+      $params['id'] = $this->id;
+    }
+
+    $result = CRM_Dataprocessor_BAO_Filter::add($params);
+
+    CRM_Utils_System::redirect($redirectUrl);
+    parent::postProcess();
+  }
+
+  /**
+   * Function to add validation rules (overrides parent function)
+   *
+   * @access public
+   */
+  function addRules() {
+    if ($this->_action != CRM_Core_Action::DELETE) {
+      $this->addFormRule(array(
+        'CRM_Dataprocessor_Form_Filter',
+        'validateName'
+      ));
+    }
+  }
+
+  /**
+   * Function to validate if rule label already exists
+   *
+   * @param array $fields
+   * @return array|bool
+   * @access static
+   */
+  static function validateName($fields) {
+    /*
+     * if id not empty, edit mode. Check if changed before check if exists
+     */
+    $id = false;
+    if (!empty($fields['id'])) {
+      $id = $fields['id'];
+    }
+    if (empty($fields['name'])) {
+      $fields['name'] = CRM_Dataprocessor_BAO_Filter::buildNameFromTitle($fields['title']);
+    }
+    if (!CRM_Dataprocessor_BAO_Filter::isNameValid($fields['name'], $fields['data_processor_id'], $id)) {
+      $errors['name'] = E::ts('There is already a filter with this name');
+      return $errors;
+    }
+    return TRUE;
+  }
+
+}
\ No newline at end of file
diff --git a/CRM/Dataprocessor/Utils/Importer.php b/CRM/Dataprocessor/Utils/Importer.php
index f30181f276d0574d329760a6a39c04ebb124706a..c1a3842d58f3368bdc0b7ebcb717a397d642f366 100644
--- a/CRM/Dataprocessor/Utils/Importer.php
+++ b/CRM/Dataprocessor/Utils/Importer.php
@@ -70,6 +70,7 @@ class CRM_Dataprocessor_Utils_Importer {
 
     // Clear all existing data sources and outputs
     CRM_Dataprocessor_BAO_Source::deleteWithDataProcessorId($id);
+    CRM_Dataprocessor_BAO_Filter::deleteWithDataProcessorId($id);
     CRM_Dataprocessor_BAO_Field::deleteWithDataProcessorId($id);
     CRM_Dataprocessor_BAO_Output::deleteWithDataProcessorId($id);
 
@@ -78,6 +79,11 @@ class CRM_Dataprocessor_Utils_Importer {
       $params['data_processor_id'] = $id;
       $result = CRM_Dataprocessor_BAO_Source::add($params);
     }
+    foreach($data['filters'] as $filter) {
+      $params = $filter;
+      $params['data_processor_id'] = $id;
+      $result = CRM_Dataprocessor_BAO_Filter::add($params);
+    }
     foreach($data['fields'] as $field) {
       $params = $field;
       $params['data_processor_id'] = $id;
diff --git a/Civi/DataProcessor/Event/FilterHandlerEvent.php b/Civi/DataProcessor/Event/FilterHandlerEvent.php
new file mode 100644
index 0000000000000000000000000000000000000000..1774c65885f33985f67d6f19b15d0a69cb9d5bcd
--- /dev/null
+++ b/Civi/DataProcessor/Event/FilterHandlerEvent.php
@@ -0,0 +1,37 @@
+<?php
+/**
+ * @author Jaap Jansma <jaap.jansma@civicoop.org>
+ * @license AGPL-3.0
+ */
+
+namespace Civi\DataProcessor\Event;
+
+use Civi\DataProcessor\DataSpecification\FieldSpecification;
+use Civi\DataProcessor\Source\SourceInterface;
+use Symfony\Component\EventDispatcher\Event;
+
+class FilterHandlerEvent extends Event {
+
+  const NAME = 'dataprocessor.filterhandler';
+
+  /**
+   * @var FieldSpecification
+   */
+  public $fieldSpecification;
+
+  /**
+   * @var SourceInterface
+   */
+  public $dataSource;
+
+  /**
+   * @var array
+   */
+  public $handlers = array();
+
+  public function __construct(FieldSpecification $field, SourceInterface $source) {
+      $this->fieldSpecification = $field;
+      $this->dataSource = $source;
+  }
+
+}
\ No newline at end of file
diff --git a/Civi/DataProcessor/Factory.php b/Civi/DataProcessor/Factory.php
index 6d478c1281cd4a7b905c710dd59c7830195382ca..dac494ce648a6dcc9200963783313e96136c5cb0 100644
--- a/Civi/DataProcessor/Factory.php
+++ b/Civi/DataProcessor/Factory.php
@@ -7,8 +7,10 @@
 namespace Civi\DataProcessor;
 
 use Civi\DataProcessor\DataSpecification\FieldSpecification;
+use Civi\DataProcessor\Event\FilterHandlerEvent;
 use Civi\DataProcessor\Event\OutputHandlerEvent;
 use Civi\DataProcessor\FieldOutputHandler\RawFieldOutputHandler;
+use Civi\DataProcessor\FilterHandler\SimpleSqlFilter;
 use Civi\DataProcessor\ProcessorType\AbstractProcessorType;
 use Civi\DataProcessor\Source\SourceInterface;
 use Symfony\Component\EventDispatcher\EventDispatcher;
@@ -201,4 +203,12 @@ class Factory {
     return $event->handlers;
   }
 
+  public function getFilterHandlers(FieldSpecification $field, SourceInterface $source) {
+    $event = new FilterHandlerEvent($field, $source);
+    $handler = new SimpleSqlFilter($field, $source);
+    $event->handlers[$handler->getName()] = $handler;
+    $this->dispatcher->dispatch(OutputHandlerEvent::NAME, $event);
+    return $event->handlers;
+  }
+
 }
\ No newline at end of file
diff --git a/Civi/DataProcessor/FieldOutputHandler/AbstractFieldOutputHandler.php b/Civi/DataProcessor/FieldOutputHandler/AbstractFieldOutputHandler.php
index 168f5539630d939df509b4b7920cefab68479869..f9d6c0daba3339414bc618f936d900e7bbd89f1d 100644
--- a/Civi/DataProcessor/FieldOutputHandler/AbstractFieldOutputHandler.php
+++ b/Civi/DataProcessor/FieldOutputHandler/AbstractFieldOutputHandler.php
@@ -7,8 +7,6 @@
 namespace Civi\DataProcessor\FieldOutputHandler;
 
 use Civi\DataProcessor\DataSpecification\FieldSpecification;
-use Civi\DataProcessor\ProcessorType\AbstractProcessorType;
-use Civi\DataProcessor\Source\SourceInterface;
 
 abstract class AbstractFieldOutputHandler {
 
diff --git a/Civi/DataProcessor/FieldOutputHandler/RawFieldOutputHandler.php b/Civi/DataProcessor/FieldOutputHandler/RawFieldOutputHandler.php
index f305db25b03b4b1005687df6cf042a43884a08b8..30fed2b78a4a35e9aa3ebe6ee3463c3f6ffa63ac 100644
--- a/Civi/DataProcessor/FieldOutputHandler/RawFieldOutputHandler.php
+++ b/Civi/DataProcessor/FieldOutputHandler/RawFieldOutputHandler.php
@@ -9,7 +9,6 @@ namespace Civi\DataProcessor\FieldOutputHandler;
 use CRM_Dataprocessor_ExtensionUtil as E;
 use Civi\DataProcessor\Source\SourceInterface;
 use Civi\DataProcessor\DataSpecification\FieldSpecification;
-use Civi\DataProcessor\ProcessorType\AbstractProcessorType;
 
 class RawFieldOutputHandler extends AbstractFieldOutputHandler {
 
diff --git a/Civi/DataProcessor/FilterHandler/AbstractFilterHandler.php b/Civi/DataProcessor/FilterHandler/AbstractFilterHandler.php
new file mode 100644
index 0000000000000000000000000000000000000000..c454c9556452153b83b1f4a29368c1173980e4cc
--- /dev/null
+++ b/Civi/DataProcessor/FilterHandler/AbstractFilterHandler.php
@@ -0,0 +1,81 @@
+<?php
+/**
+ * @author Jaap Jansma <jaap.jansma@civicoop.org>
+ * @license AGPL-3.0
+ */
+
+namespace Civi\DataProcessor\FilterHandler;
+
+use Civi\DataProcessor\DataSpecification\FieldSpecification;
+
+abstract class AbstractFilterHandler {
+
+  /**
+   * @var \Civi\DataProcessor\DataSpecification\FieldSpecification
+   */
+  protected $fieldSpecification;
+
+  /**
+   * @var bool
+   */
+  protected $is_required;
+
+  /**
+   * Returns the name of the handler type.
+   *
+   * @return String
+   */
+  abstract public function getName();
+
+  /**
+   * Returns the title of the handler type.
+   *
+   * @return String
+   */
+  abstract public function getTitle();
+
+  /**
+   * Returns the data type of this field
+   *
+   * @return String
+   */
+  abstract protected function getType();
+
+  /**
+   * @param array $filterParams
+   *   The filter settings
+   * @return mixed
+   */
+  abstract public function setFilter($filterParams);
+
+  public function __construct() {
+    $this->fieldSpecification = new FieldSpecification($this->getName(), $this->getType(), $this->getName());
+  }
+
+  /**
+   * Initialize the processor
+   *
+   * @param String $alias
+   * @param String $title
+   * @param bool $is_required
+   * @param array $configuration
+   */
+  public function initialize($alias, $title, $is_required, $configuration) {
+    // Override this in child classes.
+    $this->fieldSpecification->title = $title;
+    $this->fieldSpecification->alias = $alias;
+    $this->is_required = $is_required;
+  }
+
+  public function isRequired() {
+    return $this->is_required;
+  }
+
+  /**
+   * @return \Civi\DataProcessor\DataSpecification\FieldSpecification
+   */
+  public function getFieldSpecification() {
+    return $this->fieldSpecification;
+  }
+
+}
\ No newline at end of file
diff --git a/Civi/DataProcessor/FilterHandler/SimpleSqlFilter.php b/Civi/DataProcessor/FilterHandler/SimpleSqlFilter.php
new file mode 100644
index 0000000000000000000000000000000000000000..8c58a10941855fa74b8803b86a7fd1fd06f67ca9
--- /dev/null
+++ b/Civi/DataProcessor/FilterHandler/SimpleSqlFilter.php
@@ -0,0 +1,61 @@
+<?php
+/**
+ * @author Jaap Jansma <jaap.jansma@civicoop.org>
+ * @license AGPL-3.0
+ */
+
+namespace Civi\DataProcessor\FilterHandler;
+
+use Civi\DataProcessor\DataSpecification\FieldSpecification;
+use Civi\DataProcessor\Source\SourceInterface;
+use CRM_Dataprocessor_ExtensionUtil as E;
+
+class SimpleSqlFilter extends AbstractFilterHandler {
+
+  /**
+   * @var \Civi\DataProcessor\Source\SourceInterface
+   */
+  protected $dataSource;
+
+  public function __construct(FieldSpecification $filterField, SourceInterface $dataSource) {
+    $this->dataSource = $dataSource;
+    $this->fieldSpecification = $filterField;
+  }
+
+  /**
+   * Returns the name of the handler type.
+   *
+   * @return String
+   */
+  public function getName() {
+    return 'simple_filter_'.$this->fieldSpecification->alias;
+  }
+
+  /**
+   * Returns the data type of this field
+   *
+   * @return String
+   */
+  protected function getType() {
+    return $this->fieldSpecification->type;
+  }
+
+  /**
+   * Returns the title of this field
+   *
+   * @return String
+   */
+  public function getTitle() {
+    return E::ts('%1::%2 (Simple Filter)', array(1 => $this->dataSource->getSourceTitle(), 2 => $this->fieldSpecification->title));
+  }
+
+  /**
+   * @param array $filter
+   *   The filter settings
+   * @return mixed
+   */
+  public function setFilter($filter) {
+    $this->dataSource->addFilter($this->fieldSpecification->name, $filter);
+  }
+
+}
\ No newline at end of file
diff --git a/Civi/DataProcessor/Output/Api.php b/Civi/DataProcessor/Output/Api.php
index 3c9ec137b02717ca67b142b9c95aa470ebc24960..a9a2039e9b4594ba41cc4dbb1eefe43635a241c0 100644
--- a/Civi/DataProcessor/Output/Api.php
+++ b/Civi/DataProcessor/Output/Api.php
@@ -35,7 +35,7 @@ class Api implements OutputInterface, API_ProviderInterface, EventSubscriberInte
     // if so do our getfields stuff there.
     return array(
       Events::RESOLVE => array('onApiResolve'),
-      //Events::RESPOND => array('onGetFieldsRepsonse'), // we use this method to add our field definition to the getFields action.
+      Events::RESPOND => array('onGetFieldsRepsonse'), // we use this method to add our field definition to the getFields action.
     );
   }
 
@@ -46,6 +46,72 @@ class Api implements OutputInterface, API_ProviderInterface, EventSubscriberInte
     }
   }
 
+  /**
+   * Event listener on the ResponddEvent to handle the getfields actions.
+   * So the fields defined by the user are availble in the api explorer for example.
+   */
+  public function onGetFieldsRepsonse(RespondEvent $event) {
+    $apiRequest = $event->getApiRequest();
+    $params = $apiRequest['params'];
+    $result = $event->getResponse();
+
+    // First check whether the entity is dataprocessorapi and the action is getfields.
+    // If not return this function.
+    if (strtolower($apiRequest['entity']) != 'dataprocessorapi' || strtolower($apiRequest['action']) != 'getfields') {
+      return;
+    }
+    // Now check whether the action param is set. With the action param we can find the data processor.
+    if (isset($params['action'])) {
+      if (stripos($params['action'], 'getcount') === 0) {
+        return; // Is a get count action.
+      }
+      // Find the data processor
+      try {
+        $dataProcessor = \CRM_Dataprocessor_BAO_DataProcessor::getDataProcessorByOutputTypeAndName('api', $params['action']);
+
+        foreach ($dataProcessor->getDataFlow()->getDataSpecification()->getFields() as $fieldSpec) {
+          $field = [
+            'name' => $fieldSpec->alias,
+            'title' => $fieldSpec->title,
+            'description' => '',
+            'type' => $fieldSpec->type,
+            'api.required' => FALSE,
+            'api.aliases' => [],
+          ];
+          if ($fieldSpec->getOptions()) {
+            $field['options'] = $fieldSpec->getOptions();
+          }
+          $result['values'][$fieldSpec->alias] = $field;
+        }
+        foreach($dataProcessor->getFilterHandlers() as $filterHandler) {
+          $fieldSpec = $filterHandler->getFieldSpecification();
+          $field = [
+            'name' => $fieldSpec->alias,
+            'title' => $fieldSpec->title,
+            'description' => '',
+            'type' => $fieldSpec->type,
+            'api.required' => $filterHandler->isRequired(),
+            'api.aliases' => [],
+          ];
+          if ($fieldSpec->getOptions()) {
+            $field['options'] = $fieldSpec->getOptions();
+          }
+          if (!isset($result['values'][$fieldSpec->alias])) {
+            $result['values'][$fieldSpec->alias] = $field;
+          } else {
+            $result['values'][$fieldSpec->alias] = array_merge($result['values'][$fieldSpec->alias], $field);
+          }
+        }
+      } catch(\Exception $e) {
+        // Do nothing.
+      }
+
+      $result['count'] = count($result['values']);
+      $event->setResponse($result);
+    }
+  }
+
+
   /**
    * @param array $apiRequest
    *   The full description of the API request.
@@ -68,6 +134,29 @@ class Api implements OutputInterface, API_ProviderInterface, EventSubscriberInte
       throw new \API_Exception('Could not find a form processor');
     }
 
+    $params = $apiRequest['params'];
+    foreach($dataProcessor->getFilterHandlers() as $filter) {
+      $filterSpec = $filter->getFieldSpecification();
+      if ($filter->isRequired() && !isset($params[$filterSpec->alias])) {
+        throw new \API_Exception('Field '.$filterSpec->alias.' is required');
+      }
+      if (isset($params[$filterSpec->alias])) {
+        if (!is_array($params[$filterSpec->alias])) {
+          $filterParams = [
+            'op' => '=',
+            'value' => $params[$filterSpec->alias],
+          ];
+        } else {
+          $value = reset($params[$filterSpec->alias]);
+          $filterParams = [
+            'op' => key($params[$filterSpec->alias]),
+            'value' => $value,
+          ];
+        }
+        $filter->setFilter($filterParams);
+      }
+    }
+
     if ($isCountAction) {
       $count = $dataProcessor->getDataFlow()->recordCount();
       return array('count' => $count, 'is_error' => 0);
diff --git a/Civi/DataProcessor/ProcessorType/AbstractProcessorType.php b/Civi/DataProcessor/ProcessorType/AbstractProcessorType.php
index f8a0c75dee622e5dfbead11efc488ed2ea69def0..c977750b6b61d7a9a025f00259a183dbbf39316e 100644
--- a/Civi/DataProcessor/ProcessorType/AbstractProcessorType.php
+++ b/Civi/DataProcessor/ProcessorType/AbstractProcessorType.php
@@ -15,6 +15,7 @@ use Civi\DataProcessor\DataFlow\MultipleDataFlows\JoinSpecification;
 use Civi\DataProcessor\DataFlow\SqlDataFlow;
 use Civi\DataProcessor\DataSpecification\FieldSpecification;
 use Civi\DataProcessor\FieldOutputHandler\AbstractFieldOutputHandler;
+use Civi\DataProcessor\FilterHandler\AbstractFilterHandler;
 use Civi\DataProcessor\Storage\StorageInterface;
 
 abstract class AbstractProcessorType {
@@ -44,6 +45,11 @@ abstract class AbstractProcessorType {
    */
   protected $outputFieldHandlers;
 
+  /**
+   * @var \Civi\DataProcessor\FilterHandler\AbstractFilterHandler[]
+   */
+  protected $filterHandlers;
+
   /**
    * Add a data source to the processor
    * @param \Civi\DataProcessor\Source\SourceInterface $datasource
@@ -88,6 +94,21 @@ abstract class AbstractProcessorType {
     return $handlers;
   }
 
+  /**
+   * @return \Civi\DataProcessor\FieldOutputHandler\AbstractFilterOutputHandler[]
+   */
+  public function getAvailableFilterHandlers() {
+    $factory = dataprocessor_get_factory();
+    $handlers = array();
+    foreach($this->dataSources as $dataSource) {
+      foreach($dataSource['datasource']->getAvailableFilterFields()->getFields() as $field) {
+        $fieldHandlers = $factory->getFilterHandlers($field, $dataSource['datasource']);
+        $handlers = array_merge($handlers, $fieldHandlers);
+      }
+    }
+    return $handlers;
+  }
+
   /**
    * @param \Civi\DataProcessor\FieldOutputHandler\AbstractFieldOutputHandler $outputFieldHandler
    */
@@ -95,6 +116,20 @@ abstract class AbstractProcessorType {
     $this->outputFieldHandlers[] = $outputFieldHandler;
   }
 
+  /**
+   * @param \Civi\DataProcessor\FilterHandler\AbstractFilterHandler $filterHandler
+   */
+  public function addFilterHandler(AbstractFilterHandler $filterHandler) {
+    $this->filterHandlers[] = $filterHandler;
+  }
+
+  /**
+   * @return \Civi\DataProcessor\FilterHandler\AbstractFilterHandler[]
+   */
+  public function getFilterHandlers() {
+    return $this->filterHandlers;
+  }
+
   public function ensureFieldInDataSource(FieldSpecification $fieldSpecification) {
     foreach($this->dataSources as $dataSource) {
       $dataSource['datasource']->ensureFieldInSource($fieldSpecification);
diff --git a/Civi/DataProcessor/Source/AbstractCivicrmEntitySource.php b/Civi/DataProcessor/Source/AbstractCivicrmEntitySource.php
index 87632b783bf9d84b810e284978bc7e3cdcbd2af2..dca26b3f8dbfaa2f6462e552aafcce88256110eb 100644
--- a/Civi/DataProcessor/Source/AbstractCivicrmEntitySource.php
+++ b/Civi/DataProcessor/Source/AbstractCivicrmEntitySource.php
@@ -201,19 +201,31 @@ abstract class AbstractCivicrmEntitySource implements SourceInterface {
   protected function addFilters($configuration) {
     if (isset($configuration['filter']) && is_array($configuration['filter'])) {
       foreach($configuration['filter'] as $filter_alias => $filter_field) {
-        if ($this->getAvailableFilterFields()->doesFieldExist($filter_alias)) {
-          $spec = $this->getAvailableFilterFields()->getFieldSpecificationByName($filter_alias);
-          if ($spec instanceof CustomFieldSpecification) {
-            $customGroupDataFlowDescription = $this->ensureCustomGroup($spec->customGroupTableName, $spec->customGroupName);
-            $customGroupTableAlias = $customGroupDataFlowDescription->getDataFlow()
-              ->getTableAlias();
-            $customGroupDataFlowDescription->getDataFlow()->addWhereClause(
-              new SimpleWhereClause($customGroupTableAlias, $spec->customFieldColumnName, $filter_field['op'], $filter_field['value'])
-            );
-          } else {
-            $this->primaryDataFlow->addWhereClause(new SimpleWhereClause($this->primaryDataFlow->getTableAlias(), $spec->name, $filter_field['op'], $filter_field['value']));
-          }
-        }
+        $this->addFilter($filter_alias, $filter_field);
+      }
+    }
+  }
+
+  /**
+   * Adds an inidvidual filter to the data source
+   *
+   * @param $filter_alias
+   * @param $filter
+   *
+   * @throws \Exception
+   */
+  public function addFilter($filter_alias, $filter) {
+    if ($this->getAvailableFilterFields()->doesFieldExist($filter_alias)) {
+      $spec = $this->getAvailableFilterFields()->getFieldSpecificationByName($filter_alias);
+      if ($spec instanceof CustomFieldSpecification) {
+        $customGroupDataFlowDescription = $this->ensureCustomGroup($spec->customGroupTableName, $spec->customGroupName);
+        $customGroupTableAlias = $customGroupDataFlowDescription->getDataFlow()
+          ->getTableAlias();
+        $customGroupDataFlowDescription->getDataFlow()->addWhereClause(
+          new SimpleWhereClause($customGroupTableAlias, $spec->customFieldColumnName, $filter['op'], $filter['value'])
+        );
+      } else {
+        $this->primaryDataFlow->addWhereClause(new SimpleWhereClause($this->primaryDataFlow->getTableAlias(), $spec->name, $filter['op'], $filter['value']));
       }
     }
   }
diff --git a/api/v3/DataProcessorFilter/Create.php b/api/v3/DataProcessorFilter/Create.php
new file mode 100644
index 0000000000000000000000000000000000000000..f20d05d4a843deca67940a12b5af3b55d0ab2e4e
--- /dev/null
+++ b/api/v3/DataProcessorFilter/Create.php
@@ -0,0 +1,67 @@
+<?php
+
+use CRM_Dataprocessor_ExtensionUtil as E;
+
+/**
+ * DataProcessorFilter.Create API specification (optional)
+ * This is used for documentation and validation.
+ *
+ * @param array $spec description of filters supported by this API call
+ * @return void
+ * @see http://wiki.civicrm.org/confluence/display/CRM/API+Architecture+Standards
+ */
+function _civicrm_api3_data_processor_filter_create_spec(&$spec) {
+  $spec['id'] = array(
+		'title' => E::ts('ID'),
+		'type' => CRM_Utils_Type::T_INT,
+		'api.required' => false
+	);
+  $spec['data_processor_id'] = array(
+    'title' => E::ts('Data Processor ID'),
+    'type' => CRM_Utils_Type::T_INT,
+    'api.required' => true,
+  );
+  $spec['is_required'] = array(
+    'title' => E::ts('Is required'),
+    'type' => CRM_Utils_Type::T_BOOLEAN,
+    'api.required' => true,
+    'api.default' => true,
+  );
+  $spec['type'] = array(
+    'title' => E::ts('Type'),
+    'type' => CRM_Utils_Type::T_STRING,
+    'api.required' => true
+  );
+  $spec['name'] = array(
+    'title' => E::ts('Name'),
+    'type' => CRM_Utils_Type::T_STRING,
+    'api.required' => true
+  );
+	$spec['title'] = array(
+		'title' => E::ts('Title'),
+		'type' => CRM_Utils_Type::T_STRING,
+		'api.required' => true
+	);
+	$spec['configuration'] = array(
+    'title' => E::ts('Configuration'),
+    'type' => CRM_Utils_Type::T_TEXT,
+    'api.required' => false,
+	);
+}
+
+/**
+ * DataProcessorFilter.Create API
+ *
+ * @param array $params
+ * @return array API result descriptor
+ * @see civicrm_api3_create_success
+ * @see civicrm_api3_create_error
+ *
+ *
+ */
+function civicrm_api3_data_processor_filter_create($params) {
+  $returnValue = CRM_Dataprocessor_BAO_Filter::add($params);
+	$returnValues[$returnValue['id']] = $returnValue;
+  return civicrm_api3_create_success($returnValues, $params, 'DataProcessorFilter', 'Create');
+}
+
diff --git a/api/v3/DataProcessorFilter/Delete.php b/api/v3/DataProcessorFilter/Delete.php
new file mode 100644
index 0000000000000000000000000000000000000000..fdcb3341cb7c3ea22bcf5e43eef1fc8061bed011
--- /dev/null
+++ b/api/v3/DataProcessorFilter/Delete.php
@@ -0,0 +1,37 @@
+<?php
+
+use CRM_Dataprocessor_ExtensionUtil as E;
+
+/**
+ * DataProcessorFilter.Delete API specification (optional)
+ * This is used for documentation and validation.
+ *
+ * @param array $spec description of fields supported by this API call
+ * @return void
+ * @see http://wiki.civicrm.org/confluence/display/CRMDOC/API+Architecture+Standards
+ */
+function _civicrm_api3_data_processor_filter_Delete_spec(&$spec) {
+  $spec['id'] = array(
+		'title' => E::ts('ID'),
+		'type' => CRM_Utils_Type::T_INT,
+		'api.required' => true
+	);
+}
+
+/**
+ * DataProcessorFilter.Delete API
+ *
+ * @param array $params
+ * @return array API result descriptor
+ * @see civicrm_api3_create_success
+ * @see civicrm_api3_create_error
+ * @throws API_Exception
+ */
+function civicrm_api3_data_processor_filter_Delete($params) {
+  if (!array_key_exists('id', $params) || empty($params['id'])) {
+    throw new API_Exception('Parameter id is mandatory and can not be empty in ' . __METHOD__, 0010);
+  } else {
+    return civicrm_api3_create_success(CRM_Dataprocessor_BAO_DataProcessorFilter::deleteWithId($params['id']), $params, 'DataProcessorFilter', 'Delete');
+  }
+}
+
diff --git a/api/v3/DataProcessorFilter/Get.php b/api/v3/DataProcessorFilter/Get.php
new file mode 100644
index 0000000000000000000000000000000000000000..dbdfd8a54534e04b208dfd351ecb1d08fc09808d
--- /dev/null
+++ b/api/v3/DataProcessorFilter/Get.php
@@ -0,0 +1,30 @@
+<?php
+/**
+ * DataProcessorFilter.Get API
+ *
+ * @param array $params
+ * @return array API result descriptor
+ * @see civicrm_api3_create_success
+ * @see civicrm_api3_create_error
+ * @throws API_Exception
+ */
+function civicrm_api3_data_processor_filter_get($params) {
+  $returnValues = CRM_Dataprocessor_BAO_Filter::getValues($params);
+  return civicrm_api3_create_success($returnValues, $params, 'DataProcessorFilter', 'Get');
+}
+
+/**
+ * DataProcessorFilter.Get API specification (optional)
+ * This is used for documentation and validation.
+ *
+ * @param array $spec description of fields supported by this API call
+ * @return void
+ * @see http://wiki.civicrm.org/confluence/display/CRM/API+Architecture+Standards
+ */
+function _civicrm_api3_data_processor_filter_get_spec(&$spec) {
+	$fields = CRM_Dataprocessor_BAO_Filter::fields();
+	foreach($fields as $fieldname => $field) {
+		$spec[$fieldname] = $field;
+	}
+}
+
diff --git a/sql/create_civicrm_data_processor.sql b/sql/create_civicrm_data_processor.sql
index 2186f248018c12166ef8aa841cbc1114d01af64e..287fae8a0ab524b69541e019ddc2b4b8c1775e4c 100644
--- a/sql/create_civicrm_data_processor.sql
+++ b/sql/create_civicrm_data_processor.sql
@@ -26,6 +26,17 @@ CREATE TABLE IF NOT EXISTS `civicrm_data_processor_source` (
   PRIMARY KEY (`id`)
 ) ENGINE = InnoDB;
 
+CREATE TABLE IF NOT EXISTS `civicrm_data_processor_filter` (
+  `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
+  `data_processor_id` INT UNSIGNED NOT NULL,
+  `name` VARCHAR(128) NOT NULL,
+  `type` VARCHAR(128) NOT NULL,
+  `title` VARCHAR(128) NOT NULL,
+  `is_required` TINYINT NULL DEFAULT 1,
+  `configuration` TEXT NULL,
+  PRIMARY KEY (`id`)
+) ENGINE = InnoDB;
+
 CREATE TABLE IF NOT EXISTS `civicrm_data_processor_field` (
   `id` INT UNSIGNED NOT NULL AUTO_INCREMENT,
   `data_processor_id` INT UNSIGNED NOT NULL,
diff --git a/templates/CRM/Dataprocessor/Form/DataProcessor.tpl b/templates/CRM/Dataprocessor/Form/DataProcessor.tpl
index 6bb449cf1268cbc7401f554cfd60275c26a66bee..4d72c2c14f9bcc09df8804cd3e780bb2252de6db 100644
--- a/templates/CRM/Dataprocessor/Form/DataProcessor.tpl
+++ b/templates/CRM/Dataprocessor/Form/DataProcessor.tpl
@@ -50,6 +50,7 @@
   {if $data_processor_id}
     {include file="CRM/Dataprocessor/Form/DataProcessorBlocks/Sources.tpl"}
     {include file="CRM/Dataprocessor/Form/DataProcessorBlocks/AggregateFields.tpl"}
+    {include file="CRM/Dataprocessor/Form/DataProcessorBlocks/Filters.tpl"}
     {include file="CRM/Dataprocessor/Form/DataProcessorBlocks/Fields.tpl"}
     {include file="CRM/Dataprocessor/Form/DataProcessorBlocks/Outputs.tpl"}
   {/if}
diff --git a/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/AggregateFields.tpl b/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/AggregateFields.tpl
index 49cd0981a139e4355f97a8c18bf7dbb820bf33bf..dfab00113541ef815988638b0ca2452d75cb58f1 100644
--- a/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/AggregateFields.tpl
+++ b/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/AggregateFields.tpl
@@ -1,4 +1,5 @@
 {crmScope extensionKey='dataprocessor'}
+<h3>{ts}Aggregation{/ts}</h3>
 <div class="crm-block crm-form-block crm-data-processor_source-block">
     <table>
         <tr>
diff --git a/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/Fields.tpl b/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/Fields.tpl
index 91737000459d912888a1c5311a06c06836e7d983..92e1d1512b3b6a40f1a8596f77d2b68d912a7a62 100644
--- a/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/Fields.tpl
+++ b/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/Fields.tpl
@@ -1,4 +1,5 @@
 {crmScope extensionKey='dataprocessor'}
+<h3>{ts}Fields{/ts}</h3>
 <div class="crm-block crm-form-block crm-data-processor_source-block">
     <table>
         <tr>
diff --git a/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/Filters.tpl b/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/Filters.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..bc9f673a4a2d98830d454e39f0755d1da86ec913
--- /dev/null
+++ b/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/Filters.tpl
@@ -0,0 +1,39 @@
+{crmScope extensionKey='dataprocessor'}
+    <h3>{ts}Exposed Filters{/ts}</h3>
+    <div class="crm-block crm-form-block crm-data-processor_source-block">
+        <table>
+            <tr>
+                <th>{ts}Title{/ts}</th>
+                <th>{ts}Name{/ts}</th>
+                <th>{ts}Required{/ts}</th>
+                <th></th>
+                <th></th>
+                <th></th>
+                <th></th>
+            </tr>
+            {foreach from=$filters item=filter}
+                <tr>
+                    <td>{$filter.title}</td>
+                    <td>{$filter.name}</td>
+                    <td>{$filter.is_required}</td>
+                    <td>
+                        {if $filter.configuration_link}
+                            <a href="{$filter.configuration_link}">{ts}Configure Filter{/ts}</a>
+                        {/if}
+                    </td>
+                    <td>
+                        <a href="{crmURL p="civicrm/dataprocessor/form/filter" q="reset=1&action=update&data_processor_id=`$filter.data_processor_id`&id=`$filter.id`"}">{ts}Edit{/ts}</a>
+                    </td>
+                    <td>
+                        <a href="{crmURL p="civicrm/dataprocessor/form/filter" q="reset=1&action=delete&data_processor_id=`$filter.data_processor_id`&id=`$filter.id`"}">{ts}Remove{/ts}</a>
+                    </td>
+                </tr>
+            {/foreach}
+        </table>
+
+        <div class="crm-submit-buttons">
+            <a class="add button" title="{ts}Add Filter{/ts}" href="{$addFilterUrl}">
+                <span><div class="icon add-icon ui-icon-circle-plus"></div>{ts}Add Filter{/ts}</span></a>
+        </div>
+    </div>
+{/crmScope}
\ No newline at end of file
diff --git a/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/Outputs.tpl b/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/Outputs.tpl
index f2b3cca1e0cee0590ad80d419e7793a4b4eac90b..dfce9c8b068cf0039e8a67e49cbd219846575941 100644
--- a/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/Outputs.tpl
+++ b/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/Outputs.tpl
@@ -1,5 +1,6 @@
 {crmScope extensionKey='dataprocessor'}
-<div class="crm-block crm-form-block crm-data-processor_outputs-block">
+    <h3>{ts}Output{/ts}</h3>
+    <div class="crm-block crm-form-block crm-data-processor_outputs-block">
     <table>
         <tr>
             <th>{ts}Output{/ts}</th>
diff --git a/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/Sources.tpl b/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/Sources.tpl
index 320bf351844b624656f89dd258a1f48b052903bb..bdc57fe0f8655a4285964cc027aee397697e466a 100644
--- a/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/Sources.tpl
+++ b/templates/CRM/Dataprocessor/Form/DataProcessorBlocks/Sources.tpl
@@ -1,4 +1,5 @@
 {crmScope extensionKey='dataprocessor'}
+    <h3>{ts}Data Sources{/ts}</h3>
 <div class="crm-block crm-form-block crm-data-processor_source-block">
     <table>
         <tr>
diff --git a/templates/CRM/Dataprocessor/Form/Filter.tpl b/templates/CRM/Dataprocessor/Form/Filter.tpl
new file mode 100644
index 0000000000000000000000000000000000000000..b3afbc13dee646a041b58b28b785946b746a53c4
--- /dev/null
+++ b/templates/CRM/Dataprocessor/Form/Filter.tpl
@@ -0,0 +1,43 @@
+{crmScope extensionKey='dataprocessor'}
+<div class="crm-submit-buttons">
+    {include file="CRM/common/formButtons.tpl" location="top"}
+</div>
+
+{if $action eq 8}
+    {* Are you sure to delete form *}
+    <h3>{ts}Delete Field{/ts}</h3>
+    <div class="crm-block crm-form-block crm-data-processor_label-block">
+        <div class="crm-section">{ts 1=$filter->title}Are you sure to delete filter '%1'?{/ts}</div>
+    </div>
+{else}
+
+    {* block for rule data *}
+    <h3>{ts}Field{/ts}</h3>
+    <div class="crm-block crm-form-block crm-data-processor_source-block">
+        <div class="crm-section">
+            <div class="label">{$form.type.label}</div>
+            <div class="content">{$form.type.html}</div>
+            <div class="clear"></div>
+        </div>
+        <div class="crm-section">
+            <div class="label">{$form.title.label}</div>
+            <div class="content">{$form.title.html}</div>
+            <div class="clear"></div>
+        </div>
+        <div class="crm-section">
+            <div class="label">{$form.name.label}</div>
+            <div class="content">{$form.name.html}</div>
+            <div class="clear"></div>
+        </div>
+        <div class="crm-section">
+            <div class="label">{$form.is_required.label}</div>
+            <div class="content">{$form.is_required.html}</div>
+            <div class="clear"></div>
+        </div>
+    </div>
+{/if}
+
+<div class="crm-submit-buttons">
+    {include file="CRM/common/formButtons.tpl" location="bottom"}
+</div>
+{/crmScope}
\ No newline at end of file
diff --git a/xml/Menu/dataprocessor.xml b/xml/Menu/dataprocessor.xml
index 6b2419d315cc3b608327ed5d66b13c6dbd272ec1..a50142d723e2ce06dc1267ca0a888d2be144e37c 100644
--- a/xml/Menu/dataprocessor.xml
+++ b/xml/Menu/dataprocessor.xml
@@ -21,6 +21,13 @@
     <access_arguments>access CiviCRM</access_arguments>
     <access_arguments>administer CiviCRM</access_arguments>
   </item>
+  <item>
+    <path>civicrm/dataprocessor/form/filter</path>
+    <page_callback>CRM_Dataprocessor_Form_Filter</page_callback>
+    <title>DataProcessor</title>
+    <access_arguments>access CiviCRM</access_arguments>
+    <access_arguments>administer CiviCRM</access_arguments>
+  </item>
   <item>
     <path>civicrm/dataprocessor/form/aggregate_field</path>
     <page_callback>CRM_Dataprocessor_Form_AggregateField</page_callback>