diff --git a/src/Search.php b/src/Search.php
index a8ba0d72182a25e8069b9e1aaea7038b2f33439b..f63728b324737af216ad449b824366c673cbaeae 100644
--- a/src/Search.php
+++ b/src/Search.php
@@ -13,6 +13,9 @@ namespace ONGR\ElasticsearchDSL;
 
 use ONGR\ElasticsearchDSL\Aggregation\AbstractAggregation;
 use ONGR\ElasticsearchDSL\Highlight\Highlight;
+use ONGR\ElasticsearchDSL\SearchEndpoint\FilterEndpoint;
+use ONGR\ElasticsearchDSL\SearchEndpoint\PostFilterEndpoint;
+use ONGR\ElasticsearchDSL\SearchEndpoint\QueryEndpoint;
 use ONGR\ElasticsearchDSL\SearchEndpoint\SearchEndpointFactory;
 use ONGR\ElasticsearchDSL\SearchEndpoint\SearchEndpointInterface;
 use ONGR\ElasticsearchDSL\Serializer\Normalizer\CustomReferencedNormalizer;
@@ -110,15 +113,13 @@ class Search
      * @param BuilderInterface $query
      * @param string           $boolType
      *
-     * @return Search
+     * @return int Key of query.
      */
     public function addQuery(BuilderInterface $query, $boolType = '')
     {
-        $this
+        return $this
             ->getEndpoint('query')
             ->addBuilder($query, ['bool_type' => $boolType]);
-
-        return $this;
     }
 
     /**
@@ -128,13 +129,13 @@ class Search
      *                      - minimum_should_match => 1
      *                      - boost => 1.
      *
-     * @return Search
+     * @return $this
      */
     public function setBoolQueryParameters(array $params)
     {
-        $this
-            ->getEndpoint('query')
-            ->setParameters($params);
+        /** @var QueryEndpoint $endpoint */
+        $endpoint = $this->getEndpoint('query');
+        $endpoint->setParameters($params);
 
         return $this;
     }
@@ -142,19 +143,19 @@ class Search
     /**
      * Returns contained query.
      *
-     * @return BuilderInterface
+     * @return BuilderInterface[]
      */
     public function getQuery()
     {
         return $this
             ->getEndpoint('query')
-            ->getBuilder();
+            ->getBuilders();
     }
 
     /**
      * Destroys query part.
      *
-     * @return Search
+     * @return $this
      */
     public function destroyQuery()
     {
@@ -172,29 +173,25 @@ class Search
      *                                   - must_not
      *                                   - should.
      *
-     * @return Search
+     * @return int Key of query.
      */
     public function addFilter(BuilderInterface $filter, $boolType = '')
     {
-        $this->getEndpoint('query');
-
-        $this
+        return $this
             ->getEndpoint('filter')
             ->addBuilder($filter, ['bool_type' => $boolType]);
-
-        return $this;
     }
 
     /**
      * Returns currently contained filters.
      *
-     * @return BuilderInterface
+     * @return BuilderInterface[]
      */
     public function getFilters()
     {
         return $this
             ->getEndpoint('filter')
-            ->getBuilder();
+            ->getBuilders();
     }
 
     /**
@@ -204,13 +201,13 @@ class Search
      *                      _cache => true
      *                      false.
      *
-     * @return Search
+     * @return $this
      */
     public function setBoolFilterParameters($params)
     {
-        $this
-            ->getEndpoint('filter')
-            ->setParameters($params);
+        /** @var FilterEndpoint $endpoint */
+        $endpoint = $this->getEndpoint('filter');
+        $endpoint->setParameters($params);
 
         return $this;
     }
@@ -232,27 +229,25 @@ class Search
      *                                     - must_not
      *                                     - should.
      *
-     * @return Search
+     * @return int Key of post filter.
      */
     public function addPostFilter(BuilderInterface $postFilter, $boolType = '')
     {
-        $this
+        return $this
             ->getEndpoint('post_filter')
             ->addBuilder($postFilter, ['bool_type' => $boolType]);
-
-        return $this;
     }
 
     /**
      * Returns all contained post filters.
      *
-     * @return BuilderInterface
+     * @return BuilderInterface[]
      */
     public function getPostFilters()
     {
         return $this
             ->getEndpoint('post_filter')
-            ->getBuilder();
+            ->getBuilders();
     }
 
     /**
@@ -262,13 +257,13 @@ class Search
      *                      _cache => true
      *                      false.
      *
-     * @return Search
+     * @return $this
      */
     public function setBoolPostFilterParameters($params)
     {
-        $this
-            ->getEndpoint('post_filter')
-            ->setParameters($params);
+        /** @var PostFilterEndpoint $endpoint */
+        $endpoint = $this->getEndpoint('filter');
+        $endpoint->setParameters($params);
 
         return $this;
     }
@@ -288,7 +283,7 @@ class Search
      *
      * @param float $minScore
      *
-     * @return Search
+     * @return $this
      */
     public function setMinScore($minScore)
     {
@@ -302,7 +297,7 @@ class Search
      *
      * @param int $from
      *
-     * @return Search
+     * @return $this
      */
     public function setFrom($from)
     {
@@ -326,7 +321,7 @@ class Search
      *
      * @param int $size
      *
-     * @return Search
+     * @return $this
      */
     public function setSize($size)
     {
@@ -350,15 +345,13 @@ class Search
      *
      * @param AbstractSort $sort
      *
-     * @return Search
+     * @return int Key of sort.
      */
     public function addSort(AbstractSort $sort)
     {
-        $this
+        return $this
             ->getEndpoint('sort')
             ->addBuilder($sort);
-
-        return $this;
     }
 
     /**
@@ -370,7 +363,7 @@ class Search
     {
         return $this
             ->getEndpoint('sort')
-            ->getBuilder();
+            ->getBuilders();
     }
 
     /**
@@ -378,7 +371,7 @@ class Search
      *
      * @param array|bool|string $source
      *
-     * @return Search
+     * @return $this
      */
     public function setSource($source)
     {
@@ -402,7 +395,7 @@ class Search
      *
      * @param array $fields
      *
-     * @return Search
+     * @return $this
      */
     public function setFields(array $fields)
     {
@@ -426,7 +419,7 @@ class Search
      *
      * @param array $scriptFields
      *
-     * @return Search
+     * @return $this
      */
     public function setScriptFields($scriptFields)
     {
@@ -450,27 +443,25 @@ class Search
      *
      * @param Highlight $highlight
      *
-     * @return Search
+     * @return int Key of highlight.
      */
     public function setHighlight($highlight)
     {
-        $this
+        return $this
             ->getEndpoint('highlight')
             ->addBuilder($highlight);
-
-        return $this;
     }
 
     /**
      * Returns containing highlight object.
      *
-     * @return Highlight
+     * @return $this
      */
     public function getHighlight()
     {
         return $this
             ->getEndpoint('highlight')
-            ->getBuilder();
+            ->getBuilders();
     }
 
     /**
@@ -478,7 +469,7 @@ class Search
      *
      * @param bool $explain
      *
-     * @return Search
+     * @return $this
      */
     public function setExplain($explain)
     {
@@ -502,7 +493,7 @@ class Search
      *
      * @param array $stats
      *
-     * @return Search
+     * @return $this
      */
     public function setStats($stats)
     {
@@ -526,15 +517,13 @@ class Search
      *
      * @param AbstractAggregation $aggregation
      *
-     * @return Search
+     * @return int Key of aggregation.
      */
     public function addAggregation(AbstractAggregation $aggregation)
     {
-        $this
+        return $this
             ->getEndpoint('aggregations')
             ->addBuilder($aggregation);
-
-        return $this;
     }
 
     /**
@@ -546,7 +535,7 @@ class Search
     {
         return $this
             ->getEndpoint('aggregations')
-            ->getBuilder();
+            ->getBuilders();
     }
 
     /**
@@ -554,7 +543,7 @@ class Search
      *
      * @param string|null $duration
      *
-     * @return Search
+     * @return $this
      */
     public function setScroll($duration = '5m')
     {
@@ -578,7 +567,7 @@ class Search
      *
      * @param string $searchType
      *
-     * @return Search
+     * @return $this
      */
     public function setSearchType($searchType)
     {
@@ -612,7 +601,7 @@ class Search
      *                                custom value
      *                                string[] combination of params.
      *
-     * @return Search
+     * @return $this
      */
     public function setPreference($preferenceParams)
     {
diff --git a/src/SearchEndpoint/AbstractSearchEndpoint.php b/src/SearchEndpoint/AbstractSearchEndpoint.php
index c7ef15e379064bb8d3b57cd8a12a23df804d39e6..0480223785811dfca8e47e66f20c8722906e71c0 100644
--- a/src/SearchEndpoint/AbstractSearchEndpoint.php
+++ b/src/SearchEndpoint/AbstractSearchEndpoint.php
@@ -18,4 +18,5 @@ use ONGR\ElasticsearchDSL\Serializer\Normalizer\AbstractNormalizable;
  */
 abstract class AbstractSearchEndpoint extends AbstractNormalizable implements SearchEndpointInterface
 {
+    use BuilderContainerAwareTrait;
 }
diff --git a/src/SearchEndpoint/AggregationsEndpoint.php b/src/SearchEndpoint/AggregationsEndpoint.php
index 7c54f2d8e1fad18838beeb7febde711166e1d6bd..e9f9ae7e7d8c0ab4ea75cc41b426c0c94d0b61e7 100644
--- a/src/SearchEndpoint/AggregationsEndpoint.php
+++ b/src/SearchEndpoint/AggregationsEndpoint.php
@@ -21,6 +21,8 @@ use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
  */
 class AggregationsEndpoint implements SearchEndpointInterface
 {
+    use BuilderContainerAwareTrait;
+
     /**
      * @var NamedBuilderBag
      */
@@ -42,6 +44,8 @@ class AggregationsEndpoint implements SearchEndpointInterface
         if (count($this->bag->all()) > 0) {
             return $this->bag->toArray();
         }
+
+        return null;
     }
 
     /**
@@ -49,16 +53,42 @@ class AggregationsEndpoint implements SearchEndpointInterface
      */
     public function addBuilder(BuilderInterface $builder, $parameters = [])
     {
-        if ($builder instanceof NamedBuilderInterface) {
-            $this->bag->add($builder);
+        if (!($builder instanceof NamedBuilderInterface)) {
+            throw new \InvalidArgumentException('Builder must be named builder');
         }
+
+        $this->bag->add($builder);
+
+        return $builder->getName();
     }
 
     /**
      * {@inheritdoc}
      */
-    public function getBuilder()
+    public function getBuilders()
     {
         return $this->bag->all();
     }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getBuilder($key)
+    {
+        if (!$this->bag->has($key)) {
+            return null;
+        }
+
+        return $this->bag->get($key);
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function removeBuilder($key)
+    {
+        $this->bag->remove($key);
+
+        return $this;
+    }
 }
diff --git a/src/SearchEndpoint/BuilderContainerAwareTrait.php b/src/SearchEndpoint/BuilderContainerAwareTrait.php
new file mode 100644
index 0000000000000000000000000000000000000000..d6b3aa6e7cd8c781e9e670c69fc401734e352189
--- /dev/null
+++ b/src/SearchEndpoint/BuilderContainerAwareTrait.php
@@ -0,0 +1,99 @@
+<?php
+
+/*
+ * This file is part of the ONGR package.
+ *
+ * (c) NFQ Technologies UAB <info@nfq.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace ONGR\ElasticsearchDSL\SearchEndpoint;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+
+/**
+ * Trait to implement SearchEndpointInterface builder methods.
+ */
+trait BuilderContainerAwareTrait
+{
+    /**
+     * @var BuilderInterface[]
+     */
+    private $builderContainer = [];
+
+    /**
+     * @var array
+     */
+    private $parameterContainer = [];
+
+    /**
+     * {@inheritdoc}
+     */
+    public function addBuilder(BuilderInterface $builder, $parameters = [])
+    {
+        $this->builderContainer[] = $builder;
+        end($this->builderContainer);
+        $key = key($this->builderContainer);
+
+        $this->parameterContainer[$key] = $parameters;
+
+        return $key;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function removeBuilder($key)
+    {
+        if (array_key_exists($key, $this->builderContainer)) {
+            unset($this->builderContainer[$key]);
+            unset($this->parameterContainer[$key]);
+        }
+
+        return $this;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getBuilder($key)
+    {
+        if (array_key_exists($key, $this->builderContainer)) {
+            return $this->builderContainer[$key];
+        }
+
+        return null;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getBuilders()
+    {
+        return $this->builderContainer;
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function getBuilderParameters($key)
+    {
+        if (array_key_exists($key, $this->parameterContainer)) {
+            return $this->parameterContainer[$key];
+        }
+
+        return [];
+    }
+
+    /**
+     * {@inheritdoc}
+     */
+    public function setBuilderParameters($key, $parameters)
+    {
+        $this->parameterContainer[$key] = $parameters;
+
+        return $this;
+    }
+}
diff --git a/src/SearchEndpoint/FilterEndpoint.php b/src/SearchEndpoint/FilterEndpoint.php
index e898c40ed718c721c2305245512742915ef8b8fb..1e375095c3156b80b1ebcb30b6b50fc1b5c2e070 100644
--- a/src/SearchEndpoint/FilterEndpoint.php
+++ b/src/SearchEndpoint/FilterEndpoint.php
@@ -25,12 +25,14 @@ class FilterEndpoint extends QueryEndpoint
      */
     public function normalize(NormalizerInterface $normalizer, $format = null, array $context = [])
     {
-        if ($this->getBuilder()) {
-            $query = new FilteredQuery();
-            !$this->isBool() ? : $this->getBuilder()->setParameters($this->getParameters());
-            $query->setFilter($this->getBuilder());
-            $this->addReference('filtered_query', $query);
+        $builder = $this->getBuilderForNormalization();
+        if (empty($builder)) {
+            return;
         }
+
+        $query = new FilteredQuery();
+        $query->setFilter($builder);
+        $this->addReference('filtered_query', $query);
     }
 
     /**
diff --git a/src/SearchEndpoint/HighlightEndpoint.php b/src/SearchEndpoint/HighlightEndpoint.php
index eeaf5b7d34940c2f5310ae3c3c08d275d01b27d8..ddc61199a2449ce3b67d7e81f2ae7d9520c16e2c 100644
--- a/src/SearchEndpoint/HighlightEndpoint.php
+++ b/src/SearchEndpoint/HighlightEndpoint.php
@@ -19,8 +19,12 @@ use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
  */
 class HighlightEndpoint implements SearchEndpointInterface
 {
+    use BuilderContainerAwareTrait {
+        addBuilder as private traitAddBuilder;
+    }
+
     /**
-     * @var BuilderInterface
+     * @var int
      */
     private $highlight;
 
@@ -29,9 +33,11 @@ class HighlightEndpoint implements SearchEndpointInterface
      */
     public function normalize(NormalizerInterface $normalizer, $format = null, array $context = [])
     {
-        if ($this->getBuilder()) {
-            return $this->getBuilder()->toArray();
+        if (!$this->getBuilder($this->highlight)) {
+            return null;
         }
+
+        return $this->getBuilder($this->highlight)->toArray();
     }
 
     /**
@@ -39,14 +45,12 @@ class HighlightEndpoint implements SearchEndpointInterface
      */
     public function addBuilder(BuilderInterface $builder, $parameters = [])
     {
-        $this->highlight = $builder;
-    }
+        if ($this->getBuilders()) {
+            throw new \OverflowException('Only one highlight is expected');
+        }
+
+        $this->highlight = $this->traitAddBuilder($builder, $parameters);
 
-    /**
-     * {@inheritdoc}
-     */
-    public function getBuilder()
-    {
         return $this->highlight;
     }
 }
diff --git a/src/SearchEndpoint/PostFilterEndpoint.php b/src/SearchEndpoint/PostFilterEndpoint.php
index 3b82a8ac3cf5556eae44a73b88d0832e8a16ac23..50e2fb7b9f2e6bc7da24e76f1c51361b029b2a26 100644
--- a/src/SearchEndpoint/PostFilterEndpoint.php
+++ b/src/SearchEndpoint/PostFilterEndpoint.php
@@ -24,14 +24,15 @@ class PostFilterEndpoint extends FilterEndpoint
      */
     public function normalize(NormalizerInterface $normalizer, $format = null, array $context = [])
     {
-        if ($this->getBuilder()) {
-            $postFilter = new PostFilter();
-            !$this->isBool() ? : $this->getBuilder()->setParameters($this->getParameters());
-            $postFilter->setFilter($this->getBuilder());
+        $builder = $this->getBuilderForNormalization();
 
-            return $postFilter->toArray();
+        if (empty($builder)) {
+            return null;
         }
 
-        return null;
+        $postFilter = new PostFilter();
+        $postFilter->setFilter($builder);
+
+        return $postFilter->toArray();
     }
 }
diff --git a/src/SearchEndpoint/QueryEndpoint.php b/src/SearchEndpoint/QueryEndpoint.php
index 80db1e9be84bb2d692cb04c024088898614411f7..b8d2da882e4b8882e3c5f6c394605d1e23d202d2 100644
--- a/src/SearchEndpoint/QueryEndpoint.php
+++ b/src/SearchEndpoint/QueryEndpoint.php
@@ -12,6 +12,7 @@
 namespace ONGR\ElasticsearchDSL\SearchEndpoint;
 
 use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\Filter\BoolFilter;
 use ONGR\ElasticsearchDSL\ParametersTrait;
 use ONGR\ElasticsearchDSL\Query\BoolQuery;
 use ONGR\ElasticsearchDSL\Query\FilteredQuery;
@@ -26,11 +27,6 @@ class QueryEndpoint extends AbstractSearchEndpoint implements OrderedNormalizerI
 {
     use ParametersTrait;
 
-    /**
-     * @var BuilderInterface|BoolQuery
-     */
-    private $query;
-
     /**
      * @var OptionsResolver
      */
@@ -45,73 +41,57 @@ class QueryEndpoint extends AbstractSearchEndpoint implements OrderedNormalizerI
         $this->configureResolver($this->resolver);
     }
 
-    /**
-     * {@inheritdoc}
-     */
-    public function addBuilder(BuilderInterface $builder, $parameters = [])
-    {
-        if (!$this->query && !(array_key_exists('bool_type', $parameters) && !empty($parameters['bool_type']))) {
-            $this->setBuilder($builder);
-        } else {
-            $parameters = $this->resolver->resolve(array_filter($parameters));
-            $this->isBool() ? : $this->convertToBool();
-            $this->query->add($builder, $parameters['bool_type']);
-        }
-
-        return $this;
-    }
-
     /**
      * {@inheritdoc}
      */
     public function normalize(NormalizerInterface $normalizer, $format = null, array $context = [])
     {
-        $isRelevant = false;
-
         if ($this->hasReference('filtered_query')) {
             /** @var FilteredQuery $query */
             $query = $this->getReference('filtered_query');
             $this->addBuilder($query);
-            $isRelevant = true;
         }
 
-        if ($this->getBuilder()) {
-            if (method_exists($this->getBuilder(), 'setParameters') && count($this->getParameters()) > 0) {
-                $this
-                    ->getBuilder()
-                    ->setParameters($this->processArray($this->getBuilder()->getParameters()));
-            }
+        $builder = $this->getBuilderForNormalization();
 
-            $isRelevant = true;
+        if (empty($builder)) {
+            return null;
         }
 
-        return $isRelevant ? [$this->getBuilder()->getType() => $this->getBuilder()->toArray()] : null;
+        return [$builder->getType() => $builder->toArray()];
     }
 
     /**
-     * {@inheritdoc}
+     * Return builder that is ready to be normalized.
+     *
+     * @return BuilderInterface|null
      */
-    public function getOrder()
+    protected function getBuilderForNormalization()
     {
-        return 2;
-    }
+        $builders = $this->getbuilders();
+        if (empty($builders)) {
+            return null;
+        }
 
-    /**
-     * {@inheritdoc}
-     */
-    public function getBuilder()
-    {
-        return $this->query;
+        if (count($builders) > 1) {
+            $builder = $this->buildBool();
+        } else {
+            $builder = end($builders);
+        }
+
+        if (method_exists($builder, 'setParameters') && count($this->getParameters()) > 0) {
+            $builder->setParameters($this->processArray($builder->getParameters()));
+        }
+
+        return $builder;
     }
 
     /**
-     * Sets builder.
-     *
-     * @param BuilderInterface $builder
+     * {@inheritdoc}
      */
-    protected function setBuilder(BuilderInterface $builder)
+    public function getOrder()
     {
-        $this->query = $builder;
+        return 2;
     }
 
     /**
@@ -127,20 +107,10 @@ class QueryEndpoint extends AbstractSearchEndpoint implements OrderedNormalizerI
             );
     }
 
-    /**
-     * Returns true if query is bool.
-     *
-     * @return bool
-     */
-    protected function isBool()
-    {
-        return $this->getBuilder() instanceof BoolQuery;
-    }
-
     /**
      * Returns bool instance for this endpoint case.
      *
-     * @return BoolQuery
+     * @return BoolFilter|BoolQuery
      */
     protected function getBoolInstance()
     {
@@ -148,16 +118,19 @@ class QueryEndpoint extends AbstractSearchEndpoint implements OrderedNormalizerI
     }
 
     /**
-     * Converts query to bool.
+     * Returns bool instance with builders set.
+     *
+     * @return BoolFilter|BoolQuery
      */
-    private function convertToBool()
+    protected function buildBool()
     {
-        $bool = $this->getBoolInstance();
+        $boolInstance = $this->getBoolInstance();
 
-        if ($this->query !== null) {
-            $bool->add($this->query);
+        foreach ($this->getBuilders() as $key => $builder) {
+            $parameters = $this->resolver->resolve(array_filter($this->getBuilderParameters($key)));
+            $boolInstance->add($builder, $parameters['bool_type']);
         }
 
-        $this->query = $bool;
+        return $boolInstance;
     }
 }
diff --git a/src/SearchEndpoint/SearchEndpointInterface.php b/src/SearchEndpoint/SearchEndpointInterface.php
index bdd5dc8cd6bd064483eb081105dc3410d513e91f..1f04cea444d92c2500751da47f9640dfa25c36b6 100644
--- a/src/SearchEndpoint/SearchEndpointInterface.php
+++ b/src/SearchEndpoint/SearchEndpointInterface.php
@@ -25,14 +25,49 @@ interface SearchEndpointInterface extends NormalizableInterface
      * @param BuilderInterface $builder    Builder to add.
      * @param array            $parameters Additional parameters relevant to builder.
      *
-     * @return SearchEndpointInterface
+     * @return int Returns builder key.
      */
     public function addBuilder(BuilderInterface $builder, $parameters = []);
 
     /**
-     * Returns contained builder.
+     * Removes contained builder.
      *
-     * @return BuilderInterface|BuilderInterface[]
+     * @param int $key
+     *
+     * @return $this
+     */
+    public function removeBuilder($key);
+
+    /**
+     * Returns contained builder or null if Builder is not found.
+     *
+     * @param int $key
+     *
+     * @return BuilderInterface|null
+     */
+    public function getBuilder($key);
+
+    /**
+     * Returns all contained builders.
+     *
+     * @return BuilderInterface[]
+     */
+    public function getBuilders();
+
+    /**
+     * Returns parameters for contained builder or empty array if parameters are not found.
+     *
+     * @param int $key
+     *
+     * @return array
+     */
+    public function getBuilderParameters($key);
+
+    /**
+     * @param int   $key
+     * @param array $parameters
+     *
+     * @return $this
      */
-    public function getBuilder();
+    public function setBuilderParameters($key, $parameters);
 }
diff --git a/src/SearchEndpoint/SortEndpoint.php b/src/SearchEndpoint/SortEndpoint.php
index 578e63a126a976db1a17d2763f554dcc0dd6d582..7c14cc76c24cc6ff3507fa9c1142d888da47e4e6 100644
--- a/src/SearchEndpoint/SortEndpoint.php
+++ b/src/SearchEndpoint/SortEndpoint.php
@@ -12,6 +12,7 @@
 namespace ONGR\ElasticsearchDSL\SearchEndpoint;
 
 use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\Sort\AbstractSort;
 use ONGR\ElasticsearchDSL\Sort\Sorts;
 use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
 
@@ -20,17 +21,8 @@ use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
  */
 class SortEndpoint implements SearchEndpointInterface
 {
-    /**
-     * @var Sorts
-     */
-    protected $sorts;
-
-    /**
-     * Initializes Sorts object.
-     */
-    public function __construct()
-    {
-        $this->sorts = new Sorts();
+    use BuilderContainerAwareTrait {
+        addBuilder as private traitAddBuilder;
     }
 
     /**
@@ -38,24 +30,40 @@ class SortEndpoint implements SearchEndpointInterface
      */
     public function normalize(NormalizerInterface $normalizer, $format = null, array $context = [])
     {
-        if ($this->sorts->isRelevant()) {
-            return $this->sorts->toArray();
+        $sorts = $this->buildSorts();
+
+        if ($sorts->isRelevant()) {
+            return $sorts->toArray();
         }
+
+        return null;
     }
 
     /**
-     * {@inheritdoc}
+     * Builds sorts object.
+     *
+     * @return Sorts
      */
-    public function addBuilder(BuilderInterface $builder, $parameters = [])
+    protected function buildSorts()
     {
-        $this->sorts->addSort($builder);
+        $sorts = new Sorts();
+        /** @var AbstractSort $builder */
+        foreach ($this->getBuilders() as $builder) {
+            $sorts->addSort($builder);
+        }
+
+        return $sorts;
     }
 
     /**
      * {@inheritdoc}
      */
-    public function getBuilder()
+    public function addBuilder(BuilderInterface $builder, $parameters = [])
     {
-        return $this->sorts;
+        if (!($builder instanceof AbstractSort)) {
+            throw new \InvalidArgumentException('Sort must must a subtype of AbstractSort');
+        }
+
+        return $this->traitAddBuilder($builder, $parameters);
     }
 }
diff --git a/tests/SearchEndpoint/AggregationsEndpointTest.php b/tests/SearchEndpoint/AggregationsEndpointTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..616d872b672911dfb56bfa0afa18e45cd4cbc002
--- /dev/null
+++ b/tests/SearchEndpoint/AggregationsEndpointTest.php
@@ -0,0 +1,125 @@
+<?php
+
+/*
+ * This file is part of the ONGR package.
+ *
+ * (c) NFQ Technologies UAB <info@nfq.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace ONGR\ElasticsearchDSL\Tests\Unit\SearchEndpoint;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\NamedBuilderInterface;
+use ONGR\ElasticsearchDSL\SearchEndpoint\AggregationsEndpoint;
+use PHPUnit_Framework_MockObject_MockObject as MockObject;
+use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
+
+/**
+ * Class AggregationsEndpointTest.
+ */
+class AggregationsEndpointTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * Tests constructor.
+     */
+    public function testItCanBeInstantiated()
+    {
+        $this->assertInstanceOf(
+            'ONGR\ElasticsearchDSL\SearchEndpoint\AggregationsEndpoint',
+            new AggregationsEndpoint()
+        );
+    }
+
+    /**
+     * Tests AddBuilder.
+     */
+    public function testAddBuilder()
+    {
+        $instance = new AggregationsEndpoint();
+
+        /** @var NamedBuilderInterface|MockObject $builderInterface1 */
+        $builderInterface1 = $this->getMockForAbstractClass('ONGR\ElasticsearchDSL\NamedBuilderInterface');
+        $builderInterface1->expects($this->any())->method('getName')->willReturn('namedBuilder');
+        $key = $instance->addBuilder($builderInterface1);
+        $this->assertSame('namedBuilder', $key);
+        $this->assertSame($builderInterface1, $instance->getBuilder($key));
+
+        /** @var BuilderInterface|MockObject $builderInterface2 */
+        $builderInterface2 = $this->getMockForAbstractClass('ONGR\ElasticsearchDSL\BuilderInterface');
+
+        $this->setExpectedException('InvalidArgumentException', 'Builder must be named builder');
+        $instance->addBuilder($builderInterface2);
+    }
+
+    /**
+     * Tests removing builders.
+     */
+    public function testRemoveBuilder()
+    {
+        $instance = new AggregationsEndpoint();
+        /** @var NamedBuilderInterface|MockObject $builderInterface1 */
+        $builderInterface1 = $this->getMockForAbstractClass('ONGR\ElasticsearchDSL\NamedBuilderInterface');
+        $builderInterface1->expects($this->any())->method('getName')->willReturn('namedBuilder');
+        $key = $instance->addBuilder($builderInterface1);
+
+        $this->assertNotNull($instance->getBuilder($key));
+        $this->assertSame($instance, $instance->removeBuilder($key));
+        $this->assertNull($instance->getBuilder($key));
+    }
+
+    /**
+     * Tests getting all builders.
+     */
+    public function testGetBuilders()
+    {
+        $instance = new AggregationsEndpoint();
+        $this->assertSame([], $instance->getBuilders());
+
+        /** @var NamedBuilderInterface|MockObject $builderInterface1 */
+        $builderInterface1 = $this->getMockForAbstractClass('ONGR\ElasticsearchDSL\NamedBuilderInterface');
+        $builderInterface1->expects($this->any())->method('getName')->willReturn('namedBuilder');
+
+        $instance->addBuilder($builderInterface1);
+        $this->assertSame(['namedBuilder' => $builderInterface1], $instance->getBuilders());
+
+        /** @var NamedBuilderInterface|MockObject $builderInterface2 */
+        $builderInterface2 = $this->getMockForAbstractClass('ONGR\ElasticsearchDSL\NamedBuilderInterface');
+        $builderInterface2->expects($this->any())->method('getName')->willReturn('namedBuilder2');
+
+        $instance->addBuilder($builderInterface2);
+        $this->assertSame(
+            [
+                'namedBuilder' => $builderInterface1,
+                'namedBuilder2' => $builderInterface2,
+            ],
+            $instance->getBuilders()
+        );
+    }
+
+    /**
+     * Tests normalization builder.
+     */
+    public function testNormalization()
+    {
+        $instance = new AggregationsEndpoint();
+        /** @var NormalizerInterface|MockObject $normalizerInterface */
+        $normalizerInterface = $this->getMockForAbstractClass(
+            'Symfony\Component\Serializer\Normalizer\NormalizerInterface'
+        );
+
+        $this->assertNull($instance->normalize($normalizerInterface));
+
+        /** @var NamedBuilderInterface|MockObject $builderInterface1 */
+        $builderInterface1 = $this->getMockForAbstractClass('ONGR\ElasticsearchDSL\NamedBuilderInterface');
+        $builderInterface1->expects($this->any())->method('getName')->willReturn('namedBuilder');
+        $builderInterface1->expects($this->exactly(1))->method('toArray')->willReturn(['array' => 'data']);
+        $builderInterface1->expects($this->exactly(0))->method('getType')->willReturn('test');
+
+        $instance->addBuilder($builderInterface1);
+
+        $this->assertSame(['array' => 'data'], $instance->normalize($normalizerInterface));
+    }
+}
diff --git a/tests/SearchEndpoint/BuilderContainerAwareTraitTest.php b/tests/SearchEndpoint/BuilderContainerAwareTraitTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..d6d6a3f3c5fa56c04aacbe2a5f6075e66d35aa53
--- /dev/null
+++ b/tests/SearchEndpoint/BuilderContainerAwareTraitTest.php
@@ -0,0 +1,96 @@
+<?php
+
+/*
+ * This file is part of the ONGR package.
+ *
+ * (c) NFQ Technologies UAB <info@nfq.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace ONGR\ElasticsearchDSL\Tests\Unit\SearchEndpoint;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\SearchEndpoint\BuilderContainerAwareTrait;
+
+/**
+ * Class BuilderContainerAwareTraitTest.
+ */
+class BuilderContainerAwareTraitTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * @var BuilderContainerAwareTrait|\PHPUnit_Framework_MockObject_MockObject
+     */
+    private $instance;
+
+    /**
+     * {@inheritdoc}
+     */
+    protected function setUp()
+    {
+        parent::setUp();
+
+        $this->instance = $this->getMockForTrait('ONGR\\ElasticsearchDSL\\SearchEndpoint\\BuilderContainerAwareTrait');
+    }
+
+    /**
+     * Tests builder parameters.
+     */
+    public function testBuilderParameters()
+    {
+        $this->assertSame([], $this->instance->getBuilderParameters('non_existing_builder'));
+        $this->assertSame(
+            $this->instance,
+            $this->instance->setBuilderParameters('key', [ 'builder' => 'parameter' ])
+        );
+        $this->assertSame([ 'builder' => 'parameter' ], $this->instance->getBuilderParameters('key'));
+    }
+
+    /**
+     * Tests interactions with builders.
+     */
+    public function testBuilders()
+    {
+        $this->assertSame([], $this->instance->getBuilders());
+        $this->assertNull($this->instance->getBuilder('non_existing_builder'));
+        $this->assertSame($this->instance, $this->instance->removeBuilder('non_existing_builder'));
+
+        /** @var BuilderInterface $builder1 */
+        $builder1 = $this->getMockForAbstractClass('ONGR\ElasticsearchDSL\BuilderInterface');
+        $key1 = $this->instance->addBuilder($builder1, ['parameter' => 'value']);
+        $this->assertSame($builder1, $this->instance->getBuilder($key1));
+        $this->assertSame(['parameter' => 'value'], $this->instance->getBuilderParameters($key1));
+        $builders = $this->instance->getBuilders();
+        $this->assertCount(1, $builders);
+        $this->assertArrayHasKey($key1, $builders);
+        $this->assertSame($builder1, $builders[$key1]);
+
+        /** @var BuilderInterface $builder2 */
+        $builder2 = $this->getMockForAbstractClass('ONGR\ElasticsearchDSL\BuilderInterface');
+        $key2 = $this->instance->addBuilder($builder2, ['parameter2' => 'value2']);
+        $this->assertSame($builder2, $this->instance->getBuilder($key2));
+        $this->assertSame(['parameter2' => 'value2'], $this->instance->getBuilderParameters($key2));
+        $builders = $this->instance->getBuilders();
+        $this->assertCount(2, $builders);
+        $this->assertArrayHasKey($key1, $builders);
+        $this->assertArrayHasKey($key2, $builders);
+        $this->assertSame($builder1, $builders[$key1]);
+        $this->assertSame($builder2, $builders[$key2]);
+
+        $this->instance->removeBuilder($key2);
+        $this->assertNull($this->instance->getBuilder($key2));
+        $this->assertSame([], $this->instance->getBuilderParameters($key2));
+        $builders = $this->instance->getBuilders();
+        $this->assertCount(1, $builders);
+        $this->assertArrayHasKey($key1, $builders);
+        $this->assertArrayNotHasKey($key2, $builders);
+        $this->assertSame($builder1, $builders[$key1]);
+        $this->assertSame($builder1, ($this->instance->getBuilder($key1)));
+
+        $this->instance->removeBuilder($key1);
+        $this->assertNull($this->instance->getBuilder($key1));
+        $this->assertSame([], $this->instance->getBuilderParameters($key1));
+        $this->assertSame([], $this->instance->getBuilders());
+    }
+}
diff --git a/tests/SearchEndpoint/FilterEndpointTest.php b/tests/SearchEndpoint/FilterEndpointTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..3de6d22c04195b3d47d2fade62b4104338f062e1
--- /dev/null
+++ b/tests/SearchEndpoint/FilterEndpointTest.php
@@ -0,0 +1,85 @@
+<?php
+
+/*
+ * This file is part of the ONGR package.
+ *
+ * (c) NFQ Technologies UAB <info@nfq.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace ONGR\ElasticsearchDSL\Tests\Unit\SearchEndpoint;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\Query\FilteredQuery;
+use ONGR\ElasticsearchDSL\SearchEndpoint\FilterEndpoint;
+use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
+use PHPUnit_Framework_MockObject_MockObject as MockObject;
+
+/**
+ * Class FilterEndpointTest.
+ */
+class FilterEndpointTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * Tests constructor.
+     */
+    public function testItCanBeInstantiated()
+    {
+        $this->assertInstanceOf(
+            'ONGR\ElasticsearchDSL\SearchEndpoint\FilterEndpoint',
+            new FilterEndpoint()
+        );
+    }
+
+    /**
+     * Tests if correct order is returned.
+     */
+    public function testGetOrder()
+    {
+        $instance = new FilterEndpoint();
+        $this->assertEquals(1, $instance->getOrder());
+    }
+
+    /**
+     * Test normalization.
+     */
+    public function testNormalization()
+    {
+        $instance = new FilterEndpoint();
+        /** @var NormalizerInterface|MockObject $normalizerInterface */
+        $normalizerInterface = $this->getMockForAbstractClass(
+            'Symfony\Component\Serializer\Normalizer\NormalizerInterface'
+        );
+        $this->assertNull($instance->normalize($normalizerInterface));
+        $this->assertFalse($instance->hasReference('filtered_query'));
+
+        /** @var BuilderInterface|MockObject $builderInterface1 */
+        $builderInterface1 = $this->getMockForAbstractClass('ONGR\ElasticsearchDSL\BuilderInterface');
+        $builderInterface1->expects($this->exactly(1))->method('toArray')->willReturn(['array' => 'data']);
+        $builderInterface1->expects($this->exactly(1))->method('getType')->willReturn('test');
+        $instance->addBuilder($builderInterface1);
+
+        $this->assertNull($instance->normalize($normalizerInterface));
+        $this->assertTrue($instance->hasReference('filtered_query'));
+        /** @var FilteredQuery $reference */
+        $reference = $instance->getReference('filtered_query');
+        $this->assertInstanceOf('ONGR\ElasticsearchDSL\Query\FilteredQuery', $reference);
+        $this->assertSame($builderInterface1, $reference->getFilter());
+
+        $instance = new FilterEndpoint();
+        /** @var BuilderInterface|MockObject $builderInterface2 */
+        $builderInterface2 = $this->getMockForAbstractClass('ONGR\ElasticsearchDSL\BuilderInterface');
+        $builderInterface2->expects($this->exactly(1))->method('toArray')->willReturn(['array2' => 'data2']);
+        $builderInterface2->expects($this->exactly(1))->method('getType')->willReturn('test2');
+        $instance->addBuilder($builderInterface1);
+        $instance->addBuilder($builderInterface2);
+
+        $this->assertNull($instance->normalize($normalizerInterface));
+        $this->assertTrue($instance->hasReference('filtered_query'));
+        $reference = $instance->getReference('filtered_query');
+        $this->assertInstanceOf('ONGR\ElasticsearchDSL\Query\FilteredQuery', $reference);
+        $this->assertInstanceOf('ONGR\ElasticsearchDSL\Filter\BoolFilter', $reference->getFilter());
+    }
+}
diff --git a/tests/SearchEndpoint/HighlightEndpointTest.php b/tests/SearchEndpoint/HighlightEndpointTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..90967c66de6da76a721fde5066f6f909dec2cb2b
--- /dev/null
+++ b/tests/SearchEndpoint/HighlightEndpointTest.php
@@ -0,0 +1,70 @@
+<?php
+
+/*
+ * This file is part of the ONGR package.
+ *
+ * (c) NFQ Technologies UAB <info@nfq.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace ONGR\ElasticsearchDSL\Tests\Unit\SearchEndpoint;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\SearchEndpoint\HighlightEndpoint;
+use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
+use PHPUnit_Framework_MockObject_MockObject as MockObject;
+
+/**
+ * Class HighlightEndpointTest.
+ */
+class HighlightEndpointTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * Tests constructor.
+     */
+    public function testItCanBeInstantiated()
+    {
+        $this->assertInstanceOf('ONGR\ElasticsearchDSL\SearchEndpoint\HighlightEndpoint', new HighlightEndpoint());
+    }
+
+    /**
+     * Tests adding builder.
+     */
+    public function testAddBuilder()
+    {
+        $instance = new HighlightEndpoint();
+
+        /** @var BuilderInterface|MockObject $builderInterface1 */
+        $builderInterface1 = $this->getMockForAbstractClass('ONGR\ElasticsearchDSL\BuilderInterface');
+        $key = $instance->addBuilder($builderInterface1);
+        $this->assertNotNull($key);
+        $this->assertSame($builderInterface1, $instance->getBuilder($key));
+
+        $this->setExpectedException('OverflowException', 'Only one highlight is expected');
+        $instance->addBuilder($builderInterface1);
+    }
+
+    /**
+     * Tests adding builder.
+     */
+    public function testNormalization()
+    {
+        $instance = new HighlightEndpoint();
+        /** @var NormalizerInterface|MockObject $normalizerInterface */
+        $normalizerInterface = $this->getMockForAbstractClass(
+            'Symfony\Component\Serializer\Normalizer\NormalizerInterface'
+        );
+
+        $this->assertNull($instance->normalize($normalizerInterface));
+
+        /** @var BuilderInterface|MockObject $builderInterface1 */
+        $builderInterface1 = $this->getMockForAbstractClass('ONGR\ElasticsearchDSL\BuilderInterface');
+        $builderInterface1->expects($this->exactly(1))->method('toArray')->willReturn(['array' => 'data']);
+        $builderInterface1->expects($this->exactly(0))->method('getType')->willReturn('test');
+
+        $instance->addBuilder($builderInterface1);
+        $this->assertSame(['array' => 'data'], $instance->normalize($normalizerInterface));
+    }
+}
diff --git a/tests/SearchEndpoint/PostFilterEndpointTest.php b/tests/SearchEndpoint/PostFilterEndpointTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..857cdbc8e0b83cd9fcbd5173f04f076282616821
--- /dev/null
+++ b/tests/SearchEndpoint/PostFilterEndpointTest.php
@@ -0,0 +1,52 @@
+<?php
+
+/*
+ * This file is part of the ONGR package.
+ *
+ * (c) NFQ Technologies UAB <info@nfq.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace ONGR\ElasticsearchDSL\Tests\Unit\SearchEndpoint;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\SearchEndpoint\PostFilterEndpoint;
+use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
+use PHPUnit_Framework_MockObject_MockObject as MockObject;
+
+/**
+ * Class PostFilterEndpointTest.
+ */
+class PostFilterEndpointTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * Tests constructor.
+     */
+    public function testItCanBeInstantiated()
+    {
+        $this->assertInstanceOf('ONGR\ElasticsearchDSL\SearchEndpoint\PostFilterEndpoint', new PostFilterEndpoint());
+    }
+
+    /**
+     * Test normalization.
+     */
+    public function testNormalization()
+    {
+        $instance = new PostFilterEndpoint();
+        /** @var NormalizerInterface|MockObject $normalizerInterface */
+        $normalizerInterface = $this->getMockForAbstractClass(
+            'Symfony\Component\Serializer\Normalizer\NormalizerInterface'
+        );
+        $this->assertNull($instance->normalize($normalizerInterface));
+
+        /** @var BuilderInterface|MockObject $builderInterface1 */
+        $builderInterface1 = $this->getMockForAbstractClass('ONGR\ElasticsearchDSL\BuilderInterface');
+        $builderInterface1->expects($this->exactly(1))->method('toArray')->willReturn(['array' => 'data']);
+        $builderInterface1->expects($this->exactly(1))->method('getType')->willReturn('test');
+
+        $instance->addBuilder($builderInterface1);
+        $this->assertSame(['test' => ['array' => 'data']], $instance->normalize($normalizerInterface));
+    }
+}
diff --git a/tests/SearchEndpoint/QueryEndpointTest.php b/tests/SearchEndpoint/QueryEndpointTest.php
index 52fe8c09441477798593629afa9dad94516b296f..e22cf4a668b32bd7e4ca231990e80bd4310cb41b 100644
--- a/tests/SearchEndpoint/QueryEndpointTest.php
+++ b/tests/SearchEndpoint/QueryEndpointTest.php
@@ -11,7 +11,12 @@
 
 namespace ONGR\ElasticsearchDSL\Tests\Unit\SearchEndpoint;
 
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\Query\BoolQuery;
+use ONGR\ElasticsearchDSL\Query\FilteredQuery;
 use ONGR\ElasticsearchDSL\SearchEndpoint\QueryEndpoint;
+use PHPUnit_Framework_MockObject_MockObject as MockObject;
+use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
 
 /**
  * Unit test class for the QueryEndpoint.
@@ -25,4 +30,115 @@ class QueryEndpointTest extends \PHPUnit_Framework_TestCase
     {
         $this->assertInstanceOf('ONGR\ElasticsearchDSL\SearchEndpoint\QueryEndpoint', new QueryEndpoint());
     }
+
+    /**
+     * Tests if correct order is returned.
+     */
+    public function testGetOrder()
+    {
+        $instance = new QueryEndpoint();
+        $this->assertEquals(2, $instance->getOrder());
+    }
+
+    /**
+     * Tests if endpoint return correct normalized data.
+     */
+    public function testEndpoint()
+    {
+        $instance = new QueryEndpoint();
+        /** @var NormalizerInterface|MockObject $normalizerInterface */
+        $normalizerInterface = $this->getMockForAbstractClass(
+            'Symfony\Component\Serializer\Normalizer\NormalizerInterface'
+        );
+
+        $this->assertNull($instance->normalize($normalizerInterface));
+        /** @var BuilderInterface|MockObject $builderInterface1 */
+        $builderInterface1 = $this->getMockForAbstractClass('ONGR\ElasticsearchDSL\BuilderInterface');
+        $builderInterface1->expects($this->exactly(3))->method('toArray')->willReturn(['array' => 'data']);
+        $builderInterface1->expects($this->exactly(3))->method('getType')->willReturn('test');
+
+        $instance->addBuilder($builderInterface1);
+        $data = $instance->normalize($normalizerInterface);
+        $this->assertEquals(['test' => ['array' => 'data']], $data);
+
+        /** @var BuilderInterface|MockObject $builderInterface2 */
+        $builderInterface2 = $this->getMockForAbstractClass('ONGR\ElasticsearchDSL\BuilderInterface');
+        $builderInterface2->expects($this->exactly(2))->method('toArray')->willReturn(['array2' => 'data2']);
+        $builderInterface2->expects($this->exactly(2))->method('getType')->willReturn('test2');
+
+        $instance->addBuilder($builderInterface2);
+        $data = $instance->normalize($normalizerInterface);
+        $this->assertEquals(
+            [
+                'bool' => [
+                    'must' => [
+                        [ 'test' => [ 'array' => 'data' ] ],
+                        [ 'test2' => [ 'array2' => 'data2' ] ],
+                    ],
+                ],
+            ],
+            $data
+        );
+
+        /** @var BuilderInterface|MockObject $builderInterface3 */
+        $builderInterface3 = $this->getMockForAbstractClass('ONGR\ElasticsearchDSL\BuilderInterface');
+        $builderInterface3->expects($this->once())->method('toArray')->willReturn(['array3' => 'data3']);
+        $builderInterface3->expects($this->once())->method('getType')->willReturn('test3');
+        $instance->addBuilder($builderInterface3, ['bool_type' => BoolQuery::SHOULD]);
+        $instance->setParameters(['some' => 'parameter']);
+        $data = $instance->normalize($normalizerInterface);
+        $this->assertEquals(
+            [
+                'bool' => [
+                    'must' => [
+                        [ 'test' => [ 'array' => 'data' ] ],
+                        [ 'test2' => [ 'array2' => 'data2' ] ],
+                    ],
+                    'should' => [
+                        [ 'test3' => [ 'array3' => 'data3' ] ],
+                    ],
+                    'some' => 'parameter',
+                ],
+            ],
+            $data
+        );
+    }
+
+    /**
+     * Tests filtered query reference.
+     */
+    public function testFilteredQuery()
+    {
+        $instance = new QueryEndpoint();
+        /** @var NormalizerInterface|MockObject $normalizerInterface */
+        $normalizerInterface = $this->getMockForAbstractClass(
+            'Symfony\Component\Serializer\Normalizer\NormalizerInterface'
+        );
+        /** @var BuilderInterface|MockObject $builderInterface1 */
+        $builderInterface1 = $this->getMockForAbstractClass('ONGR\ElasticsearchDSL\BuilderInterface');
+        $builderInterface1->expects($this->exactly(1))->method('toArray')->willReturn(['array' => 'data']);
+        $builderInterface1->expects($this->exactly(1))->method('getType')->willReturn('test');
+
+        /** @var BuilderInterface|MockObject $builderInterface2 */
+        $builderInterface2 = $this->getMockForAbstractClass('ONGR\ElasticsearchDSL\BuilderInterface');
+        $builderInterface2->expects($this->exactly(1))->method('toArray')->willReturn(['array2' => 'data2']);
+        $builderInterface2->expects($this->exactly(1))->method('getType')->willReturn('test2');
+
+        $filteredQuery = new FilteredQuery($builderInterface1, $builderInterface2);
+        $instance->addReference('filtered_query', $filteredQuery);
+
+        $this->assertSame(
+            [
+                'filtered' => [
+                    'filter' => [
+                        'test2' => ['array2' => 'data2'],
+                    ],
+                    'query' => [
+                        'test' => ['array' => 'data'],
+                    ],
+                ],
+            ],
+            $instance->normalize($normalizerInterface)
+        );
+    }
 }
diff --git a/tests/SearchEndpoint/SearchEndpointFactoryTest.php b/tests/SearchEndpoint/SearchEndpointFactoryTest.php
index 5f62d2376a0c9088154e1e279f465894e28ac72b..db96ada847b867ddc237aa88e5c876558534680c 100644
--- a/tests/SearchEndpoint/SearchEndpointFactoryTest.php
+++ b/tests/SearchEndpoint/SearchEndpointFactoryTest.php
@@ -27,4 +27,12 @@ class SearchEndpointFactoryTest extends \PHPUnit_Framework_TestCase
     {
         SearchEndpointFactory::get('foo');
     }
+
+    /**
+     * Tests if factory can create endpoint.
+     */
+    public function testFactory()
+    {
+        SearchEndpointFactory::get('aggregations');
+    }
 }
diff --git a/tests/SearchEndpoint/SortEndpointTest.php b/tests/SearchEndpoint/SortEndpointTest.php
new file mode 100644
index 0000000000000000000000000000000000000000..7ae8f11fae92caf392e1ae6dce38c5c35eb44e41
--- /dev/null
+++ b/tests/SearchEndpoint/SortEndpointTest.php
@@ -0,0 +1,78 @@
+<?php
+
+/*
+ * This file is part of the ONGR package.
+ *
+ * (c) NFQ Technologies UAB <info@nfq.com>
+ *
+ * For the full copyright and license information, please view the LICENSE
+ * file that was distributed with this source code.
+ */
+
+namespace ONGR\ElasticsearchDSL\Tests\Unit\SearchEndpoint;
+
+use ONGR\ElasticsearchDSL\BuilderInterface;
+use ONGR\ElasticsearchDSL\SearchEndpoint\SortEndpoint;
+use ONGR\ElasticsearchDSL\Sort\AbstractSort;
+use PHPUnit_Framework_MockObject_MockObject as MockObject;
+use Symfony\Component\Serializer\Normalizer\NormalizerInterface;
+
+/**
+ * Class SortEndpointTest.
+ */
+class SortEndpointTest extends \PHPUnit_Framework_TestCase
+{
+    /**
+     * Tests constructor.
+     */
+    public function testItCanBeInstantiated()
+    {
+        $this->assertInstanceOf('ONGR\ElasticsearchDSL\SearchEndpoint\SortEndpoint', new SortEndpoint());
+    }
+
+    /**
+     * Tests AddBuilder.
+     */
+    public function testAddBuilder()
+    {
+        $instance = new SortEndpoint();
+
+        /** @var AbstractSort|MockObject $builderInterface1 */
+        $builderInterface1 = $this->getMockBuilder('ONGR\ElasticsearchDSL\Sort\AbstractSort')
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+
+        $key = $instance->addBuilder($builderInterface1);
+        $this->assertNotNull($key);
+        $this->assertSame($builderInterface1, $instance->getBuilder($key));
+
+        /** @var BuilderInterface|MockObject $builderInterface2 */
+        $builderInterface2 = $this->getMockForAbstractClass('ONGR\ElasticsearchDSL\BuilderInterface');
+
+        $this->setExpectedException('InvalidArgumentException', 'Sort must must a subtype of AbstractSort');
+        $instance->addBuilder($builderInterface2);
+    }
+
+    /**
+     * Tests if endpoint return correct normalized data.
+     */
+    public function testEndpoint()
+    {
+        $instance = new SortEndpoint();
+        /** @var NormalizerInterface|MockObject $normalizerInterface */
+        $normalizerInterface = $this->getMockForAbstractClass(
+            'Symfony\Component\Serializer\Normalizer\NormalizerInterface'
+        );
+        $this->assertNull($instance->normalize($normalizerInterface));
+
+        /** @var AbstractSort|MockObject $builderInterface1 */
+        $builderInterface1 = $this->getMockBuilder('ONGR\ElasticsearchDSL\Sort\AbstractSort')
+            ->disableOriginalConstructor()
+            ->getMockForAbstractClass();
+        $builderInterface1->expects($this->exactly(0))->method('toArray')->willReturn(['array' => 'data']);
+        $builderInterface1->expects($this->exactly(2))->method('getType')->willReturn('test');
+        $instance->addBuilder($builderInterface1);
+
+        $this->assertSame(['test' => ['order' => 'asc']], $instance->normalize($normalizerInterface));
+    }
+}