diff --git a/rhodecode/api/tests/test_get_repos.py b/rhodecode/api/tests/test_get_repos.py
--- a/rhodecode/api/tests/test_get_repos.py
+++ b/rhodecode/api/tests/test_get_repos.py
@@ -22,7 +22,8 @@
 import pytest
 
 from rhodecode.model.repo import RepoModel
-from rhodecode.api.tests.utils import build_data, api_call, assert_ok, jsonify
+from rhodecode.api.tests.utils import (
+    build_data, api_call, assert_ok, assert_error, jsonify)
 from rhodecode.model.db import User
 
 
@@ -40,6 +41,76 @@ class TestGetRepos(object):
         expected = ret
         assert_ok(id_, expected, given=response.body)
 
+    def test_api_get_repos_only_toplevel(self, user_util):
+        repo_group = user_util.create_repo_group(auto_cleanup=True)
+        user_util.create_repo(parent=repo_group)
+
+        id_, params = build_data(self.apikey, 'get_repos', traverse=0)
+        response = api_call(self.app, params)
+
+        result = []
+        for repo in RepoModel().get_repos_for_root(root=None):
+            result.append(repo.get_api_data(include_secrets=True))
+        expected = jsonify(result)
+
+        assert_ok(id_, expected, given=response.body)
+
+    def test_api_get_repos_with_wrong_root(self):
+        id_, params = build_data(self.apikey, 'get_repos', root='abracadabra')
+        response = api_call(self.app, params)
+
+        expected = 'Root repository group `abracadabra` does not exist'
+        assert_error(id_, expected, given=response.body)
+
+    def test_api_get_repos_with_root(self, user_util):
+        repo_group = user_util.create_repo_group(auto_cleanup=True)
+        repo_group_name = repo_group.group_name
+
+        user_util.create_repo(parent=repo_group)
+        user_util.create_repo(parent=repo_group)
+
+        # nested, should not show up
+        user_util._test_name = '{}/'.format(repo_group_name)
+        sub_repo_group = user_util.create_repo_group(auto_cleanup=True)
+        user_util.create_repo(parent=sub_repo_group)
+
+        id_, params = build_data(self.apikey, 'get_repos',
+                                 root=repo_group_name, traverse=0)
+        response = api_call(self.app, params)
+
+        result = []
+        for repo in RepoModel().get_repos_for_root(repo_group):
+            result.append(repo.get_api_data(include_secrets=True))
+
+        assert len(result) == 2
+        expected = jsonify(result)
+        assert_ok(id_, expected, given=response.body)
+
+    def test_api_get_repos_with_root_and_traverse(self, user_util):
+        repo_group = user_util.create_repo_group(auto_cleanup=True)
+        repo_group_name = repo_group.group_name
+
+        user_util.create_repo(parent=repo_group)
+        user_util.create_repo(parent=repo_group)
+
+        # nested, should not show up
+        user_util._test_name = '{}/'.format(repo_group_name)
+        sub_repo_group = user_util.create_repo_group(auto_cleanup=True)
+        user_util.create_repo(parent=sub_repo_group)
+
+        id_, params = build_data(self.apikey, 'get_repos',
+                                 root=repo_group_name, traverse=1)
+        response = api_call(self.app, params)
+
+        result = []
+        for repo in RepoModel().get_repos_for_root(
+                repo_group_name, traverse=True):
+            result.append(repo.get_api_data(include_secrets=True))
+
+        assert len(result) == 3
+        expected = jsonify(result)
+        assert_ok(id_, expected, given=response.body)
+
     def test_api_get_repos_non_admin(self):
         id_, params = build_data(self.apikey_regular, 'get_repos')
         response = api_call(self.app, params)
diff --git a/rhodecode/api/views/repo_api.py b/rhodecode/api/views/repo_api.py
--- a/rhodecode/api/views/repo_api.py
+++ b/rhodecode/api/views/repo_api.py
@@ -36,7 +36,7 @@ from rhodecode.lib.ext_json import json
 from rhodecode.model.changeset_status import ChangesetStatusModel
 from rhodecode.model.comment import ChangesetCommentsModel
 from rhodecode.model.db import (
-    Session, ChangesetStatus, RepositoryField, Repository)
+    Session, ChangesetStatus, RepositoryField, Repository, RepoGroup)
 from rhodecode.model.repo import RepoModel
 from rhodecode.model.scm import ScmModel, RepoList
 from rhodecode.model.settings import SettingsModel, VcsSettingsModel
@@ -217,7 +217,7 @@ def get_repo(request, apiuser, repoid, c
 
 
 @jsonrpc_method()
-def get_repos(request, apiuser):
+def get_repos(request, apiuser, root=Optional(None), traverse=Optional(True)):
     """
     Lists all existing repositories.
 
@@ -226,6 +226,14 @@ def get_repos(request, apiuser):
 
     :param apiuser: This is filled automatically from the |authtoken|.
     :type apiuser: AuthUser
+    :param root: specify root repository group to fetch repositories.
+        filters the returned repositories to be members of given root group.
+    :type root: Optional(None)
+    :param traverse: traverse given root into subrepositories. With this flag
+        set to False, it will only return top-level repositories from `root`.
+        if root is empty it will return just top-level repositories.
+    :type traverse: Optional(True)
+
 
     Example output:
 
@@ -257,8 +265,28 @@ def get_repos(request, apiuser):
     _perms = ('repository.read', 'repository.write', 'repository.admin',)
     extras = {'user': apiuser}
 
-    repo_list = RepoList(
-        RepoModel().get_all(), perm_set=_perms, extra_kwargs=extras)
+    root = Optional.extract(root)
+    traverse = Optional.extract(traverse, binary=True)
+
+    if root:
+        # verify parent existance, if it's empty return an error
+        parent = RepoGroup.get_by_group_name(root)
+        if not parent:
+            raise JSONRPCError(
+                'Root repository group `{}` does not exist'.format(root))
+
+        if traverse:
+            repos = RepoModel().get_repos_for_root(root=root, traverse=traverse)
+        else:
+            repos = RepoModel().get_repos_for_root(root=parent)
+    else:
+        if traverse:
+            repos = RepoModel().get_all()
+        else:
+            # return just top-level
+            repos = RepoModel().get_repos_for_root(root=None)
+
+    repo_list = RepoList(repos, perm_set=_perms, extra_kwargs=extras)
     return [repo.get_api_data(include_secrets=include_secrets)
             for repo in repo_list]
 
diff --git a/rhodecode/model/repo.py b/rhodecode/model/repo.py
--- a/rhodecode/model/repo.py
+++ b/rhodecode/model/repo.py
@@ -143,6 +143,19 @@ class RepoModel(BaseModel):
 
         return None
 
+    def get_repos_for_root(self, root, traverse=False):
+        if traverse:
+            like_expression = u'{}%'.format(safe_unicode(root))
+            repos = Repository.query().filter(
+                Repository.repo_name.like(like_expression)).all()
+        else:
+            if root and not isinstance(root, RepoGroup):
+                raise ValueError(
+                    'Root must be an instance '
+                    'of RepoGroup, got:{} instead'.format(type(root)))
+            repos = Repository.query().filter(Repository.group == root).all()
+        return repos
+
     def get_url(self, repo):
         return h.url('summary_home', repo_name=safe_str(repo.repo_name),
             qualified=True)