diff --git a/API.md b/API.md
index 4dd6d72..fe097cc 100644
--- a/API.md
+++ b/API.md
@@ -39,7 +39,7 @@
         - [Getting featured post](#getting-featured-post)
         - [Featuring post](#featuring-post)
     - Comments
-        - ~~Listing comments~~
+        - [Listing comments](#listing-comments)
         - [Creating comment](#creating-comment)
         - [Updating comment](#updating-comment)
         - [Getting comment](#getting-comment)
@@ -673,6 +673,75 @@ data.
     Features a post on the main page in web client.
 
 
+## Listing comments
+- **Request**
+
+    `GET /comments/?page=<page>&pageSize=<page-size>&query=<query>`
+
+- **Output**
+
+    ```json5
+    {
+        "query":    <query>, // same as in input
+        "page":     <page>,  // same as in input
+        "pageSize": <page-size>,
+        "total":    <total-count>,
+        "comments": [
+            <comment>,
+            <comment>,
+            <comment>
+        ]
+    }
+    ```
+    ...where `<comment>` is a [comment resource](#comment) and `query` contains
+    standard [search query](#search).
+
+- **Errors**
+
+    - privileges are too low
+
+- **Description**
+
+    Searches for comments.
+
+    **Anonymous tokens**
+
+    Same as `text` token.
+
+    **Named tokens**
+
+    | `<value>`        | Description                                    |
+    | ---------------- | ---------------------------------------------- |
+    | `id`             | specific comment ID                            |
+    | `post`           | specific post ID                               |
+    | `user`           | created by given user (accepts wildcards)      |
+    | `text`           | containing given text (accepts wildcards)      |
+    | `creation-date`  | created at given date                          |
+    | `creation-time`  | alias of `creation-date`                       |
+    | `last-edit-date` | whose most recent edit date matches given date |
+    | `last-edit-time` | alias of `last-edit-date`                      |
+    | `edit-date`      | alias of `last-edit-date`                      |
+    | `edit-time`      | alias of `last-edit-date`                      |
+
+    **Sort style tokens**
+
+    | `<value>`        | Description               |
+    | ---------------- | ------------------------- |
+    | `random`         | as random as it can get   |
+    | `user`           | author name, A to Z       |
+    | `post`           | post ID, newest to oldest |
+    | `creation-date`  | newest to oldest          |
+    | `creation-time`  | alias of `creation-date`  |
+    | `last-edit-date` | recently edited first     |
+    | `last-edit-time` | alias of `last-edit-date` |
+    | `edit-date`      | alias of `last-edit-date` |
+    | `edit-time`      | alias of `last-edit-date` |
+
+    **Special tokens**
+
+    None.
+
+
 ## Creating comment
 - **Request**
 
diff --git a/server/szurubooru/api/comment_api.py b/server/szurubooru/api/comment_api.py
index 7b26712..d1201ff 100644
--- a/server/szurubooru/api/comment_api.py
+++ b/server/szurubooru/api/comment_api.py
@@ -1,10 +1,20 @@
 import datetime
+from szurubooru import search
 from szurubooru.api.base_api import BaseApi
 from szurubooru.func import auth, comments, posts
 
 class CommentListApi(BaseApi):
+    def __init__(self):
+        super().__init__()
+        self._search_executor = search.SearchExecutor(
+            search.CommentSearchConfig())
+
     def get(self, ctx):
-        raise NotImplementedError()
+        auth.verify_privilege(ctx.user, 'comments:list')
+        return self._search_executor.execute_and_serialize(
+            ctx,
+            lambda comment: comments.serialize_comment(comment, ctx.user),
+            'comments')
 
     def post(self, ctx):
         auth.verify_privilege(ctx.user, 'comments:create')
diff --git a/server/szurubooru/search/__init__.py b/server/szurubooru/search/__init__.py
index a6c6e7f..14db2bc 100644
--- a/server/szurubooru/search/__init__.py
+++ b/server/szurubooru/search/__init__.py
@@ -4,3 +4,4 @@ from szurubooru.search.search_executor import SearchExecutor
 from szurubooru.search.user_search_config import UserSearchConfig
 from szurubooru.search.snapshot_search_config import SnapshotSearchConfig
 from szurubooru.search.tag_search_config import TagSearchConfig
+from szurubooru.search.comment_search_config import CommentSearchConfig
diff --git a/server/szurubooru/search/comment_search_config.py b/server/szurubooru/search/comment_search_config.py
new file mode 100644
index 0000000..c01979d
--- /dev/null
+++ b/server/szurubooru/search/comment_search_config.py
@@ -0,0 +1,43 @@
+from sqlalchemy.sql.expression import func
+from szurubooru import db
+from szurubooru.search.base_search_config import BaseSearchConfig
+
+class CommentSearchConfig(BaseSearchConfig):
+    def create_query(self):
+        return db.session.query(db.Comment).join(db.User)
+
+    def finalize_query(self, query):
+        return query.order_by(db.Comment.creation_time.desc())
+
+    @property
+    def anonymous_filter(self):
+        return self._create_str_filter(db.Comment.text)
+
+    @property
+    def named_filters(self):
+        return {
+            'id': self._create_num_filter(db.Comment.comment_id),
+            'post': self._create_num_filter(db.Comment.post_id),
+            'user': self._create_str_filter(db.User.name),
+            'text': self._create_str_filter(db.Comment.text),
+            'creation-date': self._create_date_filter(db.Comment.creation_time),
+            'creation-time': self._create_date_filter(db.Comment.creation_time),
+            'last-edit-date': self._create_date_filter(db.Comment.last_edit_time),
+            'last-edit-time': self._create_date_filter(db.Comment.last_edit_time),
+            'edit-date': self._create_date_filter(db.Comment.last_edit_time),
+            'edit-time': self._create_date_filter(db.Comment.last_edit_time),
+        }
+
+    @property
+    def sort_columns(self):
+        return {
+            'random': (func.random(), None),
+            'user': (db.User.name, self.SORT_ASC),
+            'post': (db.Comment.post_id, self.SORT_DESC),
+            'creation-date': (db.Comment.creation_time, self.SORT_DESC),
+            'creation-time': (db.Comment.creation_time, self.SORT_DESC),
+            'last-edit-date': (db.Comment.last_edit_time, self.SORT_DESC),
+            'last-edit-time': (db.Comment.last_edit_time, self.SORT_DESC),
+            'edit-date': (db.Comment.last_edit_time, self.SORT_DESC),
+            'edit-time': (db.Comment.last_edit_time, self.SORT_DESC),
+        }
diff --git a/server/szurubooru/search/snapshot_search_config.py b/server/szurubooru/search/snapshot_search_config.py
index 4136766..daa783d 100644
--- a/server/szurubooru/search/snapshot_search_config.py
+++ b/server/szurubooru/search/snapshot_search_config.py
@@ -14,7 +14,7 @@ class SnapshotSearchConfig(BaseSearchConfig):
             'type': self._create_str_filter(db.Snapshot.resource_type),
             'id': self._create_str_filter(db.Snapshot.resource_repr),
             'date': self._create_date_filter(db.Snapshot.creation_time),
-            'time': self._create_str_filter(db.Snapshot.creation_time),
+            'time': self._create_date_filter(db.Snapshot.creation_time),
             'operation': self._create_str_filter(db.Snapshot.operation),
             'user': self._create_str_filter(db.User.name),
         }
diff --git a/server/szurubooru/tests/api/test_comment_retrieving.py b/server/szurubooru/tests/api/test_comment_retrieving.py
index 03c7e46..1358081 100644
--- a/server/szurubooru/tests/api/test_comment_retrieving.py
+++ b/server/szurubooru/tests/api/test_comment_retrieving.py
@@ -18,9 +18,31 @@ def test_ctx(context_factory, config_injector, user_factory, comment_factory):
     ret.context_factory = context_factory
     ret.user_factory = user_factory
     ret.comment_factory = comment_factory
+    ret.list_api = api.CommentListApi()
     ret.detail_api = api.CommentDetailApi()
     return ret
 
+def test_retrieving_multiple(test_ctx):
+    comment1 = test_ctx.comment_factory(text='text 1')
+    comment2 = test_ctx.comment_factory(text='text 2')
+    db.session.add_all([comment1, comment2])
+    result = test_ctx.list_api.get(
+        test_ctx.context_factory(
+            input={'query': '', 'page': 1},
+            user=test_ctx.user_factory(rank='regular_user')))
+    assert result['query'] == ''
+    assert result['page'] == 1
+    assert result['pageSize'] == 100
+    assert result['total'] == 2
+    assert [c['text'] for c in result['comments']] == ['text 1', 'text 2']
+
+def test_trying_to_retrieve_multiple_without_privileges(test_ctx):
+    with pytest.raises(errors.AuthError):
+        test_ctx.list_api.get(
+            test_ctx.context_factory(
+                input={'query': '', 'page': 1},
+                user=test_ctx.user_factory(rank='anonymous')))
+
 def test_retrieving_single(test_ctx):
     comment = test_ctx.comment_factory(text='dummy text')
     db.session.add(comment)
diff --git a/server/szurubooru/tests/search/test_comment_search_config.py b/server/szurubooru/tests/search/test_comment_search_config.py
new file mode 100644
index 0000000..33e6510
--- /dev/null
+++ b/server/szurubooru/tests/search/test_comment_search_config.py
@@ -0,0 +1,131 @@
+import datetime
+import pytest
+from szurubooru import db, errors, search
+
+@pytest.fixture
+def executor():
+    search_config = search.CommentSearchConfig()
+    return search.SearchExecutor(search_config)
+
+@pytest.fixture
+def verify_unpaged(executor):
+    def verify(input, expected_comment_text):
+        actual_count, actual_comments = executor.execute(
+            input, page=1, page_size=100)
+        print(actual_comments)
+        actual_comment_text = [c.text for c in actual_comments]
+        assert actual_count == len(expected_comment_text)
+        assert actual_comment_text == expected_comment_text
+    return verify
+
+@pytest.mark.parametrize('input,expected_comment_text', [
+    ('creation-time:2014', ['t2', 't1']),
+    ('creation-date:2014', ['t2', 't1']),
+])
+def test_filter_by_creation_time(
+        verify_unpaged, comment_factory, input, expected_comment_text):
+    comment1 = comment_factory(text='t1')
+    comment2 = comment_factory(text='t2')
+    comment3 = comment_factory(text='t3')
+    comment1.creation_time = datetime.datetime(2014, 1, 1)
+    comment2.creation_time = datetime.datetime(2014, 6, 1)
+    comment3.creation_time = datetime.datetime(2015, 1, 1)
+    db.session.add_all([comment1, comment2, comment3])
+    verify_unpaged(input, expected_comment_text)
+
+@pytest.mark.parametrize('input,expected_comment_text', [
+    ('text:t1', ['t1']),
+    ('text:t2', ['t2']),
+    ('text:t1,t2', ['t1', 't2']),
+    ('text:t*', ['t1', 't2']),
+])
+def test_filter_by_text(
+        verify_unpaged, comment_factory, input, expected_comment_text):
+    comment1 = comment_factory(text='t1')
+    comment2 = comment_factory(text='t2')
+    db.session.add_all([comment1, comment2])
+    verify_unpaged(input, expected_comment_text)
+
+@pytest.mark.parametrize('input,expected_comment_text', [
+    ('user:u1', ['t1']),
+    ('user:u2', ['t2']),
+    ('user:u1,u2', ['t2', 't1']),
+])
+def test_filter_by_user(
+        verify_unpaged, comment_factory, user_factory, input, expected_comment_text):
+    db.session.add(comment_factory(text='t2', user=user_factory(name='u2')))
+    db.session.add(comment_factory(text='t1', user=user_factory(name='u1')))
+    verify_unpaged(input, expected_comment_text)
+
+@pytest.mark.parametrize('input,expected_comment_text', [
+    ('post:1', ['t1']),
+    ('post:2', ['t2']),
+    ('post:1,2', ['t1', 't2']),
+])
+def test_filter_by_post(
+        verify_unpaged, comment_factory, post_factory, input, expected_comment_text):
+    db.session.add(comment_factory(text='t1', post=post_factory(id=1)))
+    db.session.add(comment_factory(text='t2', post=post_factory(id=2)))
+    verify_unpaged(input, expected_comment_text)
+
+@pytest.mark.parametrize('input,expected_comment_text', [
+    ('', ['t1', 't2']),
+    ('t1', ['t1']),
+    ('t2', ['t2']),
+    ('t1,t2', ['t1', 't2']),
+])
+def test_anonymous(verify_unpaged, comment_factory, input, expected_comment_text):
+    db.session.add(comment_factory(text='t1'))
+    db.session.add(comment_factory(text='t2'))
+    verify_unpaged(input, expected_comment_text)
+
+@pytest.mark.parametrize('input,expected_comment_text', [
+    ('sort:user', ['t1', 't2']),
+])
+def test_sort_by_user(
+        verify_unpaged, comment_factory, user_factory, input, expected_comment_text):
+    db.session.add(comment_factory(text='t2', user=user_factory(name='u2')))
+    db.session.add(comment_factory(text='t1', user=user_factory(name='u1')))
+    verify_unpaged(input, expected_comment_text)
+
+@pytest.mark.parametrize('input,expected_comment_text', [
+    ('sort:post', ['t2', 't1']),
+])
+def test_sort_by_post(
+        verify_unpaged, comment_factory, post_factory, input, expected_comment_text):
+    db.session.add(comment_factory(text='t1', post=post_factory(id=1)))
+    db.session.add(comment_factory(text='t2', post=post_factory(id=2)))
+    verify_unpaged(input, expected_comment_text)
+
+@pytest.mark.parametrize('input,expected_comment_text', [
+    ('', ['t3', 't2', 't1']),
+    ('sort:creation-date', ['t3', 't2', 't1']),
+    ('sort:creation-time', ['t3', 't2', 't1']),
+])
+def test_sort_by_creation_time(
+        verify_unpaged, comment_factory, input, expected_comment_text):
+    comment1 = comment_factory(text='t1')
+    comment2 = comment_factory(text='t2')
+    comment3 = comment_factory(text='t3')
+    comment1.creation_time = datetime.datetime(1991, 1, 1)
+    comment2.creation_time = datetime.datetime(1991, 1, 2)
+    comment3.creation_time = datetime.datetime(1991, 1, 3)
+    db.session.add_all([comment3, comment1, comment2])
+    verify_unpaged(input, expected_comment_text)
+
+@pytest.mark.parametrize('input,expected_comment_text', [
+    ('sort:last-edit-date', ['t3', 't2', 't1']),
+    ('sort:last-edit-time', ['t3', 't2', 't1']),
+    ('sort:edit-date', ['t3', 't2', 't1']),
+    ('sort:edit-time', ['t3', 't2', 't1']),
+])
+def test_sort_by_last_edit_time(
+        verify_unpaged, comment_factory, input, expected_comment_text):
+    comment1 = comment_factory(text='t1')
+    comment2 = comment_factory(text='t2')
+    comment3 = comment_factory(text='t3')
+    comment1.last_edit_time = datetime.datetime(1991, 1, 1)
+    comment2.last_edit_time = datetime.datetime(1991, 1, 2)
+    comment3.last_edit_time = datetime.datetime(1991, 1, 3)
+    db.session.add_all([comment3, comment1, comment2])
+    verify_unpaged(input, expected_comment_text)
diff --git a/server/szurubooru/tests/search/test_tag_search_config.py b/server/szurubooru/tests/search/test_tag_search_config.py
index 61755fb..62e64b1 100644
--- a/server/szurubooru/tests/search/test_tag_search_config.py
+++ b/server/szurubooru/tests/search/test_tag_search_config.py
@@ -102,13 +102,13 @@ def test_sort_by_name(verify_unpaged, tag_factory, input, expected_tag_names):
     db.session.add(tag_factory(names=['t1']))
     verify_unpaged(input, expected_tag_names)
 
-@pytest.mark.parametrize('input,expected_user_names', [
+@pytest.mark.parametrize('input,expected_tag_names', [
     ('', ['t1', 't2', 't3']),
     ('sort:creation-date', ['t3', 't2', 't1']),
     ('sort:creation-time', ['t3', 't2', 't1']),
 ])
 def test_sort_by_creation_time(
-        verify_unpaged, tag_factory, input, expected_user_names):
+        verify_unpaged, tag_factory, input, expected_tag_names):
     tag1 = tag_factory(names=['t1'])
     tag2 = tag_factory(names=['t2'])
     tag3 = tag_factory(names=['t3'])
@@ -116,7 +116,7 @@ def test_sort_by_creation_time(
     tag2.creation_time = datetime.datetime(1991, 1, 2)
     tag3.creation_time = datetime.datetime(1991, 1, 3)
     db.session.add_all([tag3, tag1, tag2])
-    verify_unpaged(input, expected_user_names)
+    verify_unpaged(input, expected_tag_names)
 
 @pytest.mark.parametrize('input,expected_tag_names', [
     ('sort:suggestion-count', ['t1', 't2', 'sug1', 'sug2', 'sug3']),