diff --git a/templates/zerver/api/mark-as-read-bulk.md b/templates/zerver/api/mark-as-read-bulk.md
new file mode 100644
index 0000000000..e4986f9071
--- /dev/null
+++ b/templates/zerver/api/mark-as-read-bulk.md
@@ -0,0 +1,142 @@
+# Mark all messages as read
+
+Marks all of the current user's unread messages as read.
+
+`POST {{ api_url }}/v1/mark_all_as_read`
+
+## Usage examples
+
+
+
+
+
+
+
+```
+curl -X POST {{ api_url }}/v1/mark_all_as_read \
+ -u BOT_EMAIL_ADDRESS:BOT_API_KEY
+```
+
+
+
+
+
+{generate_code_example(python)|/mark_all_as_read:post|example}
+
+
+
+
+
+
+
+## Arguments
+
+{generate_api_arguments_table|zulip.yaml|/mark_all_as_read:post}
+
+## Response
+
+#### Example response
+
+A typical successful JSON response may look like:
+
+{generate_code_example|/mark_all_as_read:post|fixture(200)}
+
+
+# Mark messages in a stream as read
+
+Mark all the unread messages in a stream as read.
+
+`POST {{ api_url }}/v1/mark_stream_as_read`
+
+## Usage examples
+
+
+
+
+
+
+
+```
+curl -X POST {{ api_url }}/v1/mark_stream_as_read \
+ -u BOT_EMAIL_ADDRESS:BOT_API_KEY \
+ -d "stream_id=42"
+```
+
+
+
+
+
+{generate_code_example(python)|/mark_stream_as_read:post|example}
+
+
+
+
+
+
+
+## Arguments
+
+{generate_api_arguments_table|zulip.yaml|/mark_stream_as_read:post}
+
+## Response
+
+#### Example response
+
+A typical successful JSON response may look like:
+
+{generate_code_example|/mark_stream_as_read:post|fixture(200)}
+
+
+# Mark messages in a topic as read
+
+Mark all the unread messages in a topic as read.
+
+`POST {{ api_url }}/v1/mark_topic_as_read`
+
+## Usage examples
+
+
+
+
+
+
+
+```
+curl -X POST {{ api_url }}/v1/mark_topic_as_read \
+ -u BOT_EMAIL_ADDRESS:BOT_API_KEY \
+ -d "stream_id=42" \
+ -d "topic_name=new coffee machine"
+```
+
+
+
+
+
+{generate_code_example(python)|/mark_topic_as_read:post|example}
+
+
+
+
+
+
+
+## Arguments
+
+{generate_api_arguments_table|zulip.yaml|/mark_topic_as_read:post}
+
+## Response
+
+#### Example response
+
+A typical successful JSON response may look like:
+
+{generate_code_example|/mark_topic_as_read:post|fixture(200)}
diff --git a/templates/zerver/help/include/rest-endpoints.md b/templates/zerver/help/include/rest-endpoints.md
index 5bb32f0af0..6c8f8076f0 100644
--- a/templates/zerver/help/include/rest-endpoints.md
+++ b/templates/zerver/help/include/rest-endpoints.md
@@ -9,6 +9,7 @@
* [Delete a message](/api/delete-message)
* [Construct a narrow](/api/construct-narrow)
* [Get a message's edit history](/api/get-message-history)
+* [Mark messages as read in bulk](/api/mark-as-read-bulk)
#### Streams
diff --git a/zerver/lib/api_test_helpers.py b/zerver/lib/api_test_helpers.py
index e06b1d2712..d4b86ecb65 100644
--- a/zerver/lib/api_test_helpers.py
+++ b/zerver/lib/api_test_helpers.py
@@ -341,6 +341,39 @@ def toggle_mute_topic(client):
'/users/me/subscriptions/muted_topics',
'patch', '200')
+def mark_all_as_read(client):
+ # type: (Client) -> None
+
+ # {code_example|start}
+ # Mark all of the user's unread messages as read
+ result = client.mark_all_as_read()
+ # {code_example|end}
+
+ validate_against_openapi_schema(result, '/mark_all_as_read', 'post', '200')
+
+def mark_stream_as_read(client):
+ # type: (Client) -> None
+
+ # {code_example|start}
+ # Mark the unread messages in stream with ID "1" as read
+ result = client.mark_stream_as_read(1)
+ # {code_example|end}
+
+ validate_against_openapi_schema(result, '/mark_stream_as_read', 'post', '200')
+
+def mark_topic_as_read(client):
+ # type: (Client) -> None
+
+ # Grab an existing topic name
+ topìc_name = client.get_stream_topics(1)['topics'][0]['name']
+
+ # {code_example|start}
+ # Mark the unread messages in stream 1's topic "topic_name" as read
+ result = client.mark_topic_as_read(1, topìc_name)
+ # {code_example|end}
+
+ validate_against_openapi_schema(result, '/mark_stream_as_read', 'post', '200')
+
def render_message(client):
# type: (Client) -> None
@@ -666,6 +699,9 @@ def test_invalid_stream_error(client):
validate_against_openapi_schema(result, '/get_stream_id', 'get', '400')
TEST_FUNCTIONS = {
+ '/mark_all_as_read:post': mark_all_as_read,
+ '/mark_stream_as_read:post': mark_stream_as_read,
+ '/mark_topic_as_read:post': mark_topic_as_read,
'/messages/render:post': render_message,
'/messages:get': get_messages,
'/messages:post': send_message,
@@ -752,6 +788,9 @@ def test_messages(client, nonadmin_client):
get_messages(client)
get_message_history(client, message_id)
delete_message(client, message_id)
+ mark_all_as_read(client)
+ mark_stream_as_read(client)
+ mark_topic_as_read(client)
test_nonexistent_stream_error(client)
test_private_message_invalid_recipient(client)
diff --git a/zerver/openapi/zulip.yaml b/zerver/openapi/zulip.yaml
index fcdccd514d..e7d9219489 100644
--- a/zerver/openapi/zulip.yaml
+++ b/zerver/openapi/zulip.yaml
@@ -209,6 +209,68 @@ paths:
"msg": "Invalid stream name 'nonexistent'",
"result": "error"
}
+ /mark_all_as_read:
+ post:
+ description: Mark all the user's unread messages as read. This is often
+ called "bankruptcy" in Zulip.
+ security:
+ - basicAuth: []
+ responses:
+ '200':
+ description: Success.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/JsonSuccess'
+ /mark_stream_as_read:
+ post:
+ description: Mark all the unread messages in a stream as read.
+ parameters:
+ - name: stream_id
+ in: query
+ description: The ID of the stream whose messages should be marked as
+ read.
+ schema:
+ type: integer
+ example: 42
+ required: true
+ security:
+ - basicAuth: []
+ responses:
+ '200':
+ description: Success.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/JsonSuccess'
+ /mark_topic_as_read:
+ post:
+ description: Mark all the unread messages in a topic as read.
+ parameters:
+ - name: stream_id
+ in: query
+ description: The ID of the stream that contains the topic.
+ schema:
+ type: integer
+ example: 42
+ required: true
+ - name: topic_name
+ in: query
+ description: The name of the topic whose messages should be marked as
+ read.
+ schema:
+ type: string
+ example: new coffee machine
+ required: true
+ security:
+ - basicAuth: []
+ responses:
+ '200':
+ description: Success.
+ content:
+ application/json:
+ schema:
+ $ref: '#/components/schemas/JsonSuccess'
/messages:
get:
description: Fetch messages that match a specific narrow.