# This file contains the API definitions for the Zulip REST API.
#
# For details on the OpenAPI specification, see https://swagger.io/specification
#
# Our own documentation lives at
#
# https://zulip.readthedocs.io/en/latest/documentation/openapi.html
#
openapi: 3.0.1
info:
version: 1.0.0
title: Zulip REST API
description: |
Powerful open source group chat
contact:
url: https://zulip.com
license:
name: Apache 2.0
url: https://www.apache.org/licenses/LICENSE-2.0.html
servers:
# Zulip Cloud
- url: "https://{subdomain}.zulipchat.com/api/v1"
variables:
subdomain:
default: example
# Self-hosted
- url: "{server}/api/v1"
variables:
server:
default: https://
# chat.zulip.org
- url: "https://chat.zulip.org/api/v1"
# Development server
- url: "http://localhost:9991/api/v1"
security:
- basicAuth: []
#######################
# Endpoint definitions
#######################
paths:
/fetch_api_key:
post:
operationId: fetch_api_key
tags: ["authentication"]
description: |
Given a username and password, fetch the user's API key.
Used to authenticate the mobile and terminal apps when the server
has EmailAuthBackend or LDAPAuthBackend enabled.
parameters:
- name: username
in: query
description: |
The username to be used for authentication (typically, the email
address, but it could be an LDAP username).
schema:
type: string
required: true
- name: password
in: query
schema:
type: string
description: |
The user's Zulip password (or LDAP password, if LDAP authentication is in use).
required: true
responses:
"200":
description: The credentials needed to use the Zulip API.
content:
application/json:
schema:
$ref: "#/components/schemas/ApiKeyResponse"
/dev_fetch_api_key:
post:
operationId: dev_fetch_api_key
tags: ["authentication"]
description: |
For easy testing of mobile apps and other clients and against Zulip
development servers, we support fetching a Zulip API key for any user
on the development server without authentication (so that they can
implement analogues of the one-click login process available for Zulip
development servers on the web).
**Note:** This endpoint is only available on Zulip development
servers; for obvious security reasons it will always return an error
in a Zulip production server.
`POST {{ api_url }}/v1/dev_fetch_api_key`
parameters:
- name: username
in: query
description: |
The email address for the user that owns the API key.
schema:
type: string
example: iago@zulip.com
required: true
security: []
responses:
"200":
description: Success.
content:
application/json:
schema:
$ref: "#/components/schemas/ApiKeyResponse"
/events:
get:
operationId: get_events
tags: ["real_time_events"]
description: |
`GET {{ api_url }}/v1/events`
This endpoint allows you to receive new events from
[a registered event queue](/api/register-queue).
parameters:
- $ref: "#/components/parameters/QueueId"
- name: last_event_id
in: query
description: |
The highest event ID in this queue that you've received and
wish to acknowledge. See the [code for
`call_on_each_event`](https://github.com/zulip/python-zulip-api/blob/master/zulip/zulip/__init__.py)
in the [zulip Python
module](https://github.com/zulip/python-zulip-api) for an
example implementation of correctly processing each event
exactly once.
schema:
type: integer
example: -1
- name: dont_block
in: query
description: |
Set to `true` if the client is requesting a nonblocking reply. If not
specified, the request will block until either a new event is available
or a few minutes have passed, in which case the server will send the
client a heartbeat event.
schema:
type: boolean
default: false
example: true
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
events:
type: array
description: |
An array of `event` objects (possibly zero-length if `dont_block` is
set) with IDs newer than `last_event_id`. Event IDs are
guaranteed to be increasing, but they are not guaranteed to be
consecutive.
items:
oneOf:
- type: object
description: |
Event sent to a user's clients when that user's set of configured
[alert words](/help/add-an-alert-word) have changed.
properties:
id:
type: integer
type:
type: string
enum:
- alert_words
alert_words:
type: array
description: |
Array of strings, each a configured alert word.
items:
type: string
additionalProperties: false
example:
{
"type": "alert_words",
"alert_words": ["alert_word"],
"id": 0,
}
- type: object
description: |
Event sent to a user's clients when that user's display settings
have changed.
properties:
id:
type: integer
type:
type: string
enum:
- update_display_settings
setting_name:
type: string
description: |
Name of the changed display setting.
setting:
description: |
New value of the changed setting.
oneOf:
- type: boolean
- type: integer
- type: string
language_name:
description: |
Present only if the setting to be changed is
`default_language`. Contains the name of the
new default language in English.
type: string
additionalProperties: false
example:
{
"type": "update_display_settings",
"setting_name": "high_contrast_mode",
"setting": false,
}
- type: object
description: |
Event sent to a user's clients when that user's [notification
settings](/api/update-notification-settings) have changed.
properties:
id:
type: integer
type:
type: string
enum:
- update_global_notifications
notification_name:
type: string
description: |
Name of the changed notification setting.
setting:
description: |
New value of the changed setting.
oneOf:
- type: boolean
- type: integer
- type: string
additionalProperties: false
example:
{
"type": "update_global_notifications",
"notification_name": "enable_sounds",
"setting": true,
}
- type: object
description: |
Event sent generally to all users in an organization for changes
in the set of users or those users metadata.
properties:
type:
type: string
enum:
- realm_user
id:
type: integer
op:
type: string
enum:
- update
person:
description: |
Object containing the changed details of the user.
It has multiple forms depending on the value changed.
oneOf:
- type: object
description: |
When a user changes their full name.
properties:
user_id:
type: integer
description: |
The id of modified user.
full_name:
type: string
description: |
The new full name for the user.
additionalProperties: false
- type: object
description: |
When a user changes their avatar.
properties:
user_id:
type: integer
description: |
The id of the user who is affected by this change.
avatar_url:
type: string
description: |
The url of the new avatar URL for the user.
avatar_source:
type: string
description: |
The new avatar data source type for the user.
Value values are `G` (gravatar) and `U` (uploaded by user).
avatar_url_medium:
type: string
description: |
The new medium-size avatar URL for user.
avatar_version:
type: integer
description: |
The version number for the user's avatar. This is useful
for cache-busting.
additionalProperties: false
- type: object
additionalProperties: false
description: |
When a user changes their timezone setting.
properties:
user_id:
type: integer
description: |
The id of modified user.
email:
type: string
description: |
The email of the user.
**Deprecated**: This field will be removed in a future
release as it is redunant with the `user_id`.
deprecated: true
timezone:
type: string
description: |
The new timezone of the user.
- type: object
additionalProperties: false
description: |
When the owner of a bot changes.
properties:
user_id:
type: integer
description: |
The id of the user/bot whose owner has changed.
bot_owner_id:
type: integer
description: |
The user id of the new bot owner.
- type: object
additionalProperties: false
description: |
When the role of a user changes.
properties:
user_id:
type: integer
description: |
The id of the user affected by this change.
role:
type: integer
description: |
The new role of the user in integer.
- type: object
additionalProperties: false
description: |
When the delivery email of a user changes.
Note: This event is only visible to admins.
properties:
user_id:
type: integer
description: |
The id of the user affected by this change.
delivery_email:
type: string
description: |
The new delivery email of the user.
- type: object
additionalProperties: false
description: |
When the user updates one of their custom profile
fields.
properties:
user_id:
type: integer
description: |
The id of the user affected by this change.
custom_profile_field:
type: object
additionalProperties: false
description: |
Object containing details about the custom
profile data change.
properties:
id:
type: integer
description: |
The id of the custom profile field which user updated.
value:
type: string
description: |
User's personal value for this custom profile field.
rendered_value:
type: string
description: |
The `value` rendered in HTML. Will only be present for
custom profile field types that support markdown rendering.
This user-generated HTML content should be rendered
using the same CSS and client-side security protections
as are used for message content.
additionalProperties: false
example:
{
"type": "realm_user",
"op": "update",
"person":
{
"avatar_source": "G",
"avatar_url": "https:\/\/secure.gravatar.com\/avatar\/6d8cad0fd00256e7b40691d27ddfd466?d=identicon&version=3",
"avatar_url_medium": "https:\/\/secure.gravatar.com\/avatar\/6d8cad0fd00256e7b40691d27ddfd466?d=identicon&s=500&version=3",
"avatar_version": 3,
"user_id": 10,
},
"id": 0,
}
- type: object
description: |
Event sent to a user's clients when that user's stream subscriptions
have changed (either the set of subscriptions or their properties).
properties:
id:
type: integer
type:
type: string
enum:
- subscription
op:
type: string
enum:
- add
subscriptions:
type: array
description: |
A list of dictionaries where each dictionary contains
information about one of the subscribed streams.
items:
$ref: "#/components/schemas/Subscriptions"
additionalProperties: false
example:
{
"type": "subscription",
"op": "add",
"subscriptions":
[
{
"name": "test_stream",
"stream_id": 9,
"description": "",
"rendered_description": "",
"invite_only": false,
"is_web_public": false,
"stream_post_policy": 1,
"history_public_to_subscribers": true,
"first_message_id": null,
"message_retention_days": null,
"is_announcement_only": false,
"color": "#76ce90",
"is_muted": false,
"pin_to_top": false,
"audible_notifications": null,
"desktop_notifications": null,
"email_notifications": null,
"push_notifications": null,
"wildcard_mentions_notify": null,
"in_home_view": true,
"email_address": "test_stream.af64447e9e39374841063747ade8e6b0.show-sender@testserver",
"stream_weekly_traffic": null,
"subscribers": [10],
},
],
"id": 0,
}
- type: object
description: |
Event type for messages.
properties:
id:
type: integer
type:
type: string
enum:
- message
message:
$ref: "#/components/schemas/Messages"
flags:
type: array
description: |
The user's [message flags][message-flags] for the message.
items:
type: string
email_notified:
type: boolean
description: |
Whether the user receiving the event has already been
notified via email.
push_notified:
type: boolean
description: |
Whether the user receiving the event has already been
notified via mobile notification.
stream_push_notify:
type: boolean
description: |
Whether the user receiving the event has to be notified
via mobile notification for stream message.
stream_email_notify:
type: boolean
description: |
Whether the user receiving the event has to be notified
via email for stream message.
wildcard_mention_notify:
type: boolean
description: |
Whether the user has to be notified due to wildcard mention.
additionalProperties: false
example:
{
"type": "message",
"message":
{
"id": 31,
"sender_id": 10,
"content": "
First message ...zulip.txt<\/a><\/p>",
"recipient_id": 23,
"timestamp": 1594825416,
"client": "test suite",
"subject": "test",
"topic_links": [],
"is_me_message": false,
"reactions": [],
"submessages": [],
"sender_full_name": "King Hamlet",
"sender_short_name": "hamlet",
"sender_email": "user10@zulip.testserver",
"sender_realm_str": "zulip",
"display_recipient": "Denmark",
"type": "stream",
"stream_id": 1,
"avatar_url": null,
"content_type": "text\/html",
},
"flags": [],
"id": 1,
}
queue_id:
type: string
description: |
The ID of the registered queue.
- example:
{
"queue_id": "1375801870:2942",
"events":
[
{
"id": 0,
"message":
{
"avatar_url": "https://url/for/othello-bots/avatar",
"client": "website",
"content": "I come not, friends, to steal away your hearts.",
"content_type": "text/x-markdown",
"display_recipient": "Denmark",
"id": 12345678,
"recipient_id": 12314,
"sender_email": "othello-bot@example.com",
"sender_full_name": "Othello Bot",
"sender_id": 13215,
"sender_realm_str": "example",
"topic": "Castle",
"topic_links": [],
"timestamp": 1375978403,
"type": "stream",
},
"type": "message",
},
{
"id": 1,
"message":
{
"avatar_url": "https://url/for/othello-bots/avatar",
"client": "website",
"content": "With mirth and laughter let old wrinkles come.",
"content_type": "text/x-markdown",
"display_recipient":
[
{
"email": "hamlet@example.com",
"full_name": "Hamlet of Denmark",
"id": 31572,
},
],
"id": 12345679,
"recipient_id": 18391,
"sender_email": "othello-bot@example.com",
"sender_full_name": "Othello Bot",
"sender_id": 13215,
"sender_realm_str": "example",
"subject": "",
"topic_links": [],
"timestamp": 1375978404,
"type": "private",
},
"type": "message",
},
],
"msg": "",
"result": "success",
}
"400":
description: Bad request.
content:
application/json:
schema:
$ref: "#/components/schemas/BadEventQueueIdError"
delete:
operationId: delete_queue
tags: ["real_time_events"]
description: |
Delete a previously registered queue.
`DELETE {{ api_url }}/v1/events`
parameters:
- $ref: "#/components/parameters/QueueId"
responses:
"200":
description: Success.
content:
application/json:
schema:
$ref: "#/components/schemas/JsonSuccess"
"400":
description: Bad request.
content:
application/json:
schema:
$ref: "#/components/schemas/BadEventQueueIdError"
/get_stream_id:
get:
operationId: get_stream_id
tags: ["streams"]
description: |
Get the unique ID of a given stream.
`GET {{ api_url }}/v1/get_stream_id`
parameters:
- $ref: "#/components/parameters/Stream"
required: true
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
stream_id:
type: integer
description: |
The ID of the given stream.
- example: {"msg": "", "result": "success", "stream_id": 15}
"400":
description: Bad request.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/CodedError"
- example:
{
"code": "BAD_REQUEST",
"msg": "Invalid stream name 'nonexistent'",
"result": "error",
}
/mark_all_as_read:
post:
operationId: mark_all_as_read
tags: ["messages"]
description: |
Marks all of the current user's unread messages as read.
`POST {{ api_url }}/v1/mark_all_as_read`
responses:
"200":
description: Success.
content:
application/json:
schema:
$ref: "#/components/schemas/JsonSuccess"
/mark_stream_as_read:
post:
operationId: mark_stream_as_read
tags: ["messages"]
description: |
Mark all the unread messages in a stream as read.
parameters:
- $ref: "#/components/parameters/StreamIdInQuery"
required: true
responses:
"200":
description: Success.
content:
application/json:
schema:
$ref: "#/components/schemas/JsonSuccess"
/mark_topic_as_read:
post:
operationId: mark_topic_as_read
tags: ["messages"]
description: |
Mark all the unread messages in a topic as read.
parameters:
- $ref: "#/components/parameters/StreamIdInQuery"
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
responses:
"200":
description: Success.
content:
application/json:
schema:
$ref: "#/components/schemas/JsonSuccess"
/attachments:
get:
operationId: get_attachments
tags: ["users"]
description: |
Fetch metadata on files uploaded by the requesting user.
`GET {{ api_url }}/v1/attachments`
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
attachments:
type: array
description: |
A list of `attachment` objects, each containing
details about a file uploaded by the user.
items:
type: object
additionalProperties: false
properties:
id:
type: integer
description: |
The unique ID for the attachment.
name:
type: string
description: |
Name of the uploaded file.
path_id:
type: string
description: |
A representation of the path of the file within the
repository of user-uploaded files. If the `path_id` of a
file is `{realm_id}/ab/cdef/temp_file.py`, its URL will be:
`{server_url}/user_uploads/{realm_id}/ab/cdef/temp_file.py`.
size:
type: integer
description: |
Size of the file in bytes.
create_time:
type: integer
description: |
Time when the attachment was uploaded as a UNIX timestamp
multiplied by 1000 (matching the format of getTime() in JavaScript).
**Changes**: Changed in Zulip 2.2 (feature level 22). This field was
previously a floating point number.
messages:
type: array
description: |
Contains basic details on any Zulip messages that have been
sent referencing this [uploaded file](/api/upload-file).
This includes messages sent by any user in the Zulip
organization who sent a message containing a link to the
uploaded file.
items:
type: object
additionalProperties: false
properties:
date_sent:
type: integer
description: |
Time when the message was sent as a UNIX timestamp
multiplied by 1000 (matching the format of getTime() in JavaScript).
**Changes**: Changed in Zulip 2.2 (feature level 22). This
field was previously strangely called `name` and was a floating
point number.
id:
type: integer
description: |
The unique message ID. Messages should always be
displayed sorted by ID.
upload_space_used:
type: integer
description: |
The total size of all files uploaded by in the organization,
in bytes.
- example:
{
"result": "success",
"msg": "",
"attachments":
[
{
"id": 1,
"name": "166050.jpg",
"path_id": "2/ce/DfOkzwdg_IwlrN3myw3KGtiJ/166050.jpg",
"size": 571946,
"create_time": 1588145417000,
"messages":
[
{"id": 102, "date_sent": 1588145424000},
{"id": 103, "date_sent": 1588145448000},
],
},
],
"upload_space_used": 571946,
}
/messages:
get:
operationId: get_messages
tags: ["messages"]
description: |
Fetch message history from a Zulip server.
`GET {{ api_url }}/v1/messages`
This `GET /api/v1/messages` endpoint is the primary way to fetch
message history from a Zulip server. It is useful both for Zulip
clients (e.g. the web, desktop, mobile, and terminal clients) as well
as bots, API clients, backup scripts, etc.
By specifying a [narrow filter](/api/construct-narrow), you can use
this endpoint to fetch the messages matching any search query that is
supported by Zulip's powerful full-text search backend.
When a narrow is not specified, it can be used to fetch a user's
message history (We recommend paginating to 1000 messages at a time).
In either case, you specify an `anchor` message (or ask the server to
calculate the first unread message for you and use that as the
anchor), as well as a number of messages before and after the anchor
message. The server returns those messages, sorted by message ID, as
well as some metadata that makes it easy for a client to determine
whether there are more messages matching the query that were not
returned due to the `num_before` and `num_after` limits.
We recommend using `num_before <= 1000` and `num_after <= 1000` to
avoid generating very large HTTP responses. A maximum of 5000 messages
can be obtained per request; attempting to exceed this will result in an
error.
parameters:
- name: anchor
in: query
description: |
Integer message ID to anchor fetching of new messages. Supports special
string values for when the client wants the server to compute the anchor
to use:
* `newest`: The most recent message.
* `oldest`: The oldest message.
* `first_unread`: The oldest unread message matching the
query, if any; otherwise, the most recent message.
The special values of `'newest'` and `'oldest'` are also supported
for anchoring the query at the most recent or oldest messages.
**Changes**: String values are new in Zulip 3.0 (feature level 1). The
`first_unread` functionality was supported in Zulip 2.1.x
and older by not sending anchor and using use_first_unread_anchor.
In Zulip 2.1.x and older, `oldest` can be emulated with
`anchor=0`, and `newest` with `anchor=10000000000000000`
(that specific large value works around a bug in Zulip
2.1.x and older in the `found_newest` return value).
schema:
oneOf:
- type: string
- type: integer
example: 42
- name: num_before
in: query
description: |
The number of messages with IDs less than the anchor to retrieve.
schema:
type: integer
minimum: 0
example: 4
required: true
- name: num_after
in: query
description: |
The number of messages with IDs greater than the anchor to retrieve.
schema:
type: integer
minimum: 0
example: 8
required: true
- name: narrow
in: query
description: |
The narrow where you want to fetch the messages from. See how to
[construct a narrow](/api/construct-narrow).
content:
application/json:
schema:
type: array
items:
type: object
default: []
example: [{"operand": "Denmark", "operator": "stream"}]
- $ref: "#/components/parameters/ClientGravatar"
- name: apply_markdown
in: query
description: |
If `true`, message content is returned in the rendered HTML
format. If `false`, message content is returned in the raw
markdown-format text that user entered.
schema:
type: boolean
default: true
example: false
- name: use_first_unread_anchor
in: query
deprecated: true
description: |
Legacy way to specify `anchor="first_unread"` in Zulip 2.1.x and older.
Whether to use the (computed by the server) first unread message
matching the narrow as the `anchor`. Mutually exclusive with `anchor`.
**Changes**: Deprecated in Zulip 3.0, replaced by
`anchor="first_unread"` instead.
schema:
type: boolean
default: false
example: true
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
anchor:
type: integer
description: |
The same `anchor` specified in the request (or the computed one, if
`use_first_unread_anchor` is `true`).
found_newest:
type: boolean
description: |
Whether the `messages` list includes the very newest messages matching
the narrow (used by clients that paginate their requests to decide
whether there are more messages to fetch).
found_oldest:
type: boolean
description: |
Whether the `messages` list includes the very oldest messages matching
the narrow (used by clients that paginate their requests to decide
whether there are more messages to fetch).
found_anchor:
type: boolean
description: |
Whether the anchor message is included in the
response. If the message with the ID specified
in the request does not exist or did not match
the narrow, this will be false.
history_limited:
type: boolean
description: |
Whether the message history was limited due to
plan restrictions. This flag is set to `true`
only when the oldest messages(`found_oldest`)
matching the narrow is fetched.
messages:
type: array
description: |
an array of `message` objects, each containing the following
fields:
items:
$ref: "#/components/schemas/GetMessages"
- example:
{
"anchor": 21,
"found_newest": true,
"found_anchor": true,
"result": "success",
"msg": "",
"messages":
[
{
"subject": "",
"sender_realm_str": "zulip",
"type": "private",
"content": "Security experts agree that relational algorithms are an interesting new topic in the field of networking, and scholars concur.
",
"flags": ["read"],
"id": 16,
"display_recipient":
[
{
"id": 4,
"is_mirror_dummy": false,
"email": "hamlet@zulip.com",
"full_name": "King Hamlet",
},
{
"id": 5,
"is_mirror_dummy": false,
"email": "iago@zulip.com",
"full_name": "Iago",
},
{
"id": 8,
"is_mirror_dummy": false,
"email": "prospero@zulip.com",
"full_name": "Prospero from The Tempest",
},
],
"content_type": "text/html",
"is_me_message": false,
"timestamp": 1527921326,
"sender_id": 4,
"sender_full_name": "King Hamlet",
"recipient_id": 27,
"topic_links": [],
"client": "populate_db",
"avatar_url": "https://secure.gravatar.com/avatar/6d8cad0fd00256e7b40691d27ddfd466?d=identicon&version=1",
"submessages": [],
"sender_email": "hamlet@zulip.com",
"reactions": [],
},
{
"subject": "Verona3",
"stream_id": 5,
"sender_realm_str": "zulip",
"type": "stream",
"content": "Wait, is this from the frontend js code or backend python code
",
"flags": ["read"],
"id": 21,
"display_recipient": "Verona",
"content_type": "text/html",
"is_me_message": false,
"timestamp": 1527939746,
"sender_id": 4,
"sender_full_name": "King Hamlet",
"recipient_id": 20,
"topic_links": [],
"client": "populate_db",
"avatar_url": "https://secure.gravatar.com/avatar/6d8cad0fd00256e7b40691d27ddfd466?d=identicon&version=1",
"submessages": [],
"sender_email": "hamlet@zulip.com",
"reactions": [],
},
],
}
post:
operationId: send_message
tags: ["messages"]
description: |
Send a stream or a private message.
`POST {{ api_url }}/v1/messages`
parameters:
- name: type
in: query
description: |
The type of message to be sent. `private` for a private message and
`stream` for a stream message.
schema:
type: string
enum:
- private
- stream
example: private
required: true
- name: to
in: query
description: |
For stream messages, either the name or integer ID of the stream. For
private messages, either a list containing integer user IDs or a list
containing string email addresses.
**Changes**: Support for using user/stream IDs was added in Zulip 2.0.0.
content:
application/json:
schema:
type: array
items:
type: integer
example: [9, 10]
required: true
- $ref: "#/components/parameters/RequiredContent"
- $ref: "#/components/parameters/Topic"
- name: queue_id
in: query
schema:
type: string
description: |
For clients supporting
[local echo](https://zulip.readthedocs.io/en/latest/subsystems/sending-messages.html#local-echo),
the [event queue](/api/register-queue)
ID for the client. If passed, `local_id` is required. If the message is
successfully sent, the server will include `local_id` in the `message` event
that the client with this `queue_id` will receive notifying it of the new message
via [`GET /events`](/api/get-events). This lets the client know unambiguously
that it should replace the locally echoed message, rather than adding this new
message (which would be correct if the user had sent the new message from another
device).
example: "1593114627:0"
- name: local_id
in: query
schema:
type: string
description: |
For clients supporting local echo, a unique string-format identifier
chosen freely by the client; the server will pass it back to the client without
inspecting it, as described in the `queue_id` description.
example: "100.01"
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
id:
type: integer
description: |
The unique ID assigned to the sent message.
deliver_at:
type: string
description: |
Present for scheduled messages, encodes the time when the message will
be sent. Note that scheduled messages ("Send later") is a beta API and
may change before it's a finished feature.
example: "2020-06-24 11:19:54.337533+00:00"
- example: {"msg": "", "id": 42, "result": "success"}
"400":
description: Bad request.
content:
application/json:
schema:
oneOf:
- $ref: "#/components/schemas/NonExistingStreamError"
- allOf:
- $ref: "#/components/schemas/CodedError"
- example:
{
"code": "BAD_REQUEST",
"msg": "Invalid email 'eeshan@zulip.com'",
"result": "error",
}
/messages/{message_id}/history:
get:
operationId: get_message_history
tags: ["messages"]
description: |
Fetch the message edit history of a previously edited message.
`GET {{ api_url }}/v1/messages/{message_id}/history`
Note that edit history may be disabled in some organizations; see the
[Zulip Help Center documentation on editing messages][edit-settings].
[edit-settings]: /help/view-a-messages-edit-history
parameters:
- $ref: "#/components/parameters/MessageId"
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
message_history:
type: array
items:
type: object
additionalProperties: false
properties:
topic:
type: string
description: |
the topic for the message.
prev_topic:
type: string
description: |
the topic for the message before being edited.
content:
type: string
description: |
the body of the message.
rendered_content:
type: string
description: |
the already rendered, HTML version of `content`.
prev_content:
type: string
description: |
the body of the message before being edited.
prev_rendered_content:
type: string
description: |
the already rendered, HTML version of
`prev_content`.
user_id:
type: integer
description: |
the ID of the user that made the edit.
content_html_diff:
type: string
description: |
an HTML diff between this version of the message
and the previous one.
timestamp:
type: integer
description: |
the UNIX timestamp for this edit.
description: |
A chronologically sorted array of `snapshot`
objects, each one with the values of the
message after the edit.
- example:
{
"message_history":
[
{
"content": "Hello!",
"topic": "party at my houz",
"rendered_content": "Hello!
",
"timestamp": 1530129122,
"user_id": 5,
},
{
"topic": "party at my house",
"content": "Howdy!",
"prev_content": "Hello!",
"rendered_content": "Howdy!
",
"user_id": 5,
"prev_rendered_content": "Hello!
",
"content_html_diff": '',
"prev_topic": "party at my houz",
"timestamp": 1530129134,
},
],
"msg": "",
"result": "success",
}
"400":
description: Bad request.
content:
application/json:
schema:
$ref: "#/components/schemas/InvalidMessageError"
/messages/flags:
post:
operationId: update_message_flags
tags: ["messages"]
description: |
Add or remove personal message flags like `read` and `starred`
on a collection of message IDs.
`POST {{ api_url }}/v1/messages/flags`
For updating the `read` flag on common collections of messages, see also
the
[special endpoints for marking message as read in bulk](/api/mark-all-as-read).
parameters:
- name: messages
in: query
description: |
An array containing the IDs of the target messages.
content:
application/json:
schema:
type: array
items:
type: integer
example: [4, 8, 15]
required: true
- name: op
in: query
description: |
Whether to `add` the flag or `remove` it.
schema:
type: string
enum:
- add
- remove
example: add
required: true
- name: flag
in: query
description: |
The flag that should be added/removed.
schema:
type: string
example: read
required: true
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
messages:
type: array
items:
type: integer
description: |
An array with the IDs of the modified messages.
- example:
{"msg": "", "messages": [4, 18, 15], "result": "success"}
/messages/render:
post:
operationId: render_message
tags: ["messages"]
description: |
Render a message to HTML.
`POST {{ api_url }}/v1/messages/render`
parameters:
- $ref: "#/components/parameters/RequiredContent"
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
rendered:
type: string
description: |
The rendered HTML.
- example:
{
"msg": "",
"rendered": "foo
",
"result": "success",
}
/messages/{message_id}/reactions:
post:
operationId: add_reaction
tags: ["messages"]
description: |
Add an [emoji reaction](/help/emoji-reactions) to a message.
`POST {{ api_url }}/v1/messages/{message_id}/reactions`
parameters:
- $ref: "#/components/parameters/MessageId"
- $ref: "#/components/parameters/EmojiName"
required: true
- $ref: "#/components/parameters/EmojiCode"
- $ref: "#/components/parameters/ReactionType"
responses:
"200":
$ref: "#/components/responses/SimpleSuccess"
"400":
description: Bad request.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/CodedError"
- example:
{
"result": "error",
"msg": "Invalid emoji code",
"code": "BAD_REQUEST",
}
delete:
operationId: remove_reaction
tags: ["messages"]
description: |
Remove an [emoji reaction](/help/emoji-reactions) from a message.
`DELETE {{ api_url }}/v1/messages/{message_id}/reactions`
parameters:
- $ref: "#/components/parameters/MessageId"
- $ref: "#/components/parameters/EmojiName"
required: false
- $ref: "#/components/parameters/EmojiCode"
- $ref: "#/components/parameters/ReactionType"
responses:
"200":
$ref: "#/components/responses/SimpleSuccess"
"400":
description: Bad request.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/CodedError"
- example:
{
"result": "error",
"msg": "Invalid message(s)",
"code": "BAD_REQUEST",
}
/messages/matches_narrow:
get:
operationId: check_messages_match_narrow
tags: ["messages"]
description: |
Check whether a set of messages match a [narrow](/api/construct-narrow).
`GET {{ api_url }}/v1/messages/matches_narrow`
For many common narrows (E.g. a topic), clients can write an
efficient client-side check to determine whether a
newly arrived message belongs in the view.
This endpoint is designed to allow clients to handle more complex narrows
for which the client does not (or in the case of full-text search,
cannot) implement this check.
The format of the `match_subject` and `match_content` objects is designed to match
those of `GET /messages`, so that a client can splice these fields into a
`message` object received from `GET /events` and end up with an extended message
object identical to how a `GET /messages` for the current narrow would have
returned the message.
parameters:
- name: msg_ids
in: query
description: List of IDs for the messages to check.
content:
application/json:
schema:
type: array
items:
type: integer
example: [31, 32]
required: true
- name: narrow
in: query
description:
A structure defining the narrow to check against. See how to
[construct a narrow](/api/construct-narrow).
content:
application/json:
schema:
type: array
items:
type: object
example: [{"operator": "has", "operand": "link"}]
required: true
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
messages:
type: object
description: |
A dictionary with a key for each queried message that matches the narrow,
with message IDs as keys and search rendering data as values.
additionalProperties:
type: object
additionalProperties: false
properties:
match_content:
type: string
description: |
HTML content of a queried message that matches the narrow. If the
narrow is a search narrow, `` elements
will be included, wrapping the matches for the search keywords.
match_subject:
type: string
description: |
HTML-escaped topic of a queried message that matches the narrow. If the
narrow is a search narrow, `` elements
will be included wrapping the matches for the search keywords.
description: |
The ID of the message that matches the narrow. No record will be returned
for queried messages that do not match the narrow.
- example:
{
"result": "success",
"msg": "",
"messages":
{
"31":
{
"match_content": 'http://foo.com
',
"match_subject": "test_topic",
},
},
}
/messages/{message_id}:
get:
operationId: get_raw_message
tags: ["messages"]
description: |
Get the raw content of a message.
`GET {{ api_url }}/v1/messages/{msg_id}`
This is a rarely-used endpoint relevant for clients that primarily
work with HTML-rendered messages but might need to occasionally fetch
the message's raw markdown (e.g. for pre-filling a message-editing
UI).
parameters:
- $ref: "#/components/parameters/MessageId"
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
raw_content:
type: string
description: |
The raw content of the message.
- example:
{
"raw_content": "**Don't** forget your towel!",
"result": "success",
"msg": "",
}
"400":
description: Bad request.
content:
application/json:
schema:
$ref: "#/components/schemas/InvalidMessageError"
patch:
operationId: update_message
tags: ["messages"]
description: |
Edit/update the content or topic of a message.
`PATCH {{ api_url }}/v1/messages/{msg_id}`
`{msg_id}` in the above URL should be replaced with the ID of the
message you wish you update.
parameters:
- $ref: "#/components/parameters/MessageId"
- $ref: "#/components/parameters/Topic"
- name: propagate_mode
in: query
description: |
Which message(s) should be edited: just the one indicated in
`message_id`, messages in the same topic that had been sent after this
one, or all of them.
schema:
type: string
enum:
- change_one
- change_later
- change_all
default: change_one
example: change_all
- name: send_notification_to_old_thread
in: query
description: |
Whether to send breadcrumb message to the old thread to
notify users where the messages were moved to.
**Changes**: New in Zulip 3.0 (feature level 9).
schema:
type: boolean
default: true
example: true
- name: send_notification_to_new_thread
in: query
description: |
Whether to send a notification message to the new thread to
notify users where the messages came from.
**Changes**: New in Zulip 3.0 (feature level 9).
schema:
type: boolean
default: true
example: true
- $ref: "#/components/parameters/OptionalContent"
- $ref: "#/components/parameters/StreamIdInQuery"
responses:
"200":
description: Success.
content:
application/json:
schema:
$ref: "#/components/schemas/JsonSuccess"
"400":
description: Bad request.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/CodedError"
- properties:
msg:
enum:
- Your organization has turned off message editing
- You don't have permission to edit this message
- The time limit for editing this message has past
- Nothing to change
- Topic can't be empty
- example:
{
"code": "BAD_REQUEST",
"msg": "You don't have permission to edit this message",
"result": "error",
}
delete:
operationId: delete_message
tags: ["messages"]
description: |
Permanently delete a message.
`DELETE {{ api_url }}/v1/messages/{msg_id}`
This API corresponds to the
[delete a message completely][delete-completely] feature documented in
the Zulip Help Center.
parameters:
- $ref: "#/components/parameters/MessageId"
responses:
"200":
description: Success.
content:
application/json:
schema:
$ref: "#/components/schemas/JsonSuccess"
"400":
description: Bad request.
content:
application/json:
schema:
oneOf:
- $ref: "#/components/schemas/InvalidMessageError"
- allOf:
- $ref: "#/components/schemas/CodedError"
- example:
{
"code": "BAD_REQUEST",
"msg": "You don't have permission to delete this message",
"result": "error",
}
/user_uploads:
post:
operationId: upload_file
tags: ["messages"]
description: |
Upload a single file and get the corresponding URI.
`POST {{ api_url }}/v1/user_uploads`
Initially, only you will be able to access the link. To share the
uploaded file, you'll need to [send a message][send-message]
containing the resulting link. Users who can already access the link
can reshare it with other users by sending additional Zulip messages
containing the link.
[uploaded-files]: /help/manage-your-uploaded-files
[send-message]: /api/send-message
requestBody:
content:
multipart/form-data:
schema:
properties:
filename:
type: string
format: binary
example: /path/to/file
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
uri:
type: string
description: |
The URI of the uploaded file.
- example:
{
"msg": "",
"result": "success",
"uri": "/user_uploads/1/4e/m2A3MSqFnWRLUf9SaPzQ0Up_/zulip.txt",
}
/user_uploads/{realm_id_str}/{filename}:
get:
operationId: get_file_temporary_url
tags: ["messages"]
description: |
Get a temporary URL for access to the file that doesn't require authentication.
parameters:
- name: realm_id_str
in: path
description: |
The realm id.
schema:
type: integer
example: 1
required: true
- name: filename
in: path
description: |
Path to the URL.
schema:
type: string
example: 4e/m2A3MSqFnWRLUf9SaPzQ0Up_/zulip.txt
required: true
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
url:
type: string
description: |
A temporary URL that can be used to access the uploaded file
without Zulip's normal API authentication.
- example:
{
"msg": "",
"result": "success",
"url": "/user_uploads/temporary/322F32632F39765378464E4C63306D3961396F4970705A4D74424565432F7A756C69702E7478743A316A5053616A3A3938625F44393446466D37357254315F4F414C425A4553464F6A55",
}
/users:
get:
operationId: get_users
tags: ["users"]
description: |
Retrieve details on all users in the organization. Optionally
includes values of [custom profile field](/help/add-custom-profile-fields).
`GET {{ api_url }}/v1/users`
parameters:
- $ref: "#/components/parameters/ClientGravatar"
- $ref: "#/components/parameters/IncludeCustomProfileFields"
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
members:
type: array
description: |
A list of `user` objects, each containing details about a user in the
organization.
items:
$ref: "#/components/schemas/User"
- example:
{
"msg": "",
"result": "success",
"members":
[
{
"is_active": true,
"email": "AARON@zulip.com",
"is_admin": false,
"is_owner": false,
"avatar_url": "https://secure.gravatar.com/avatar/818c212b9f8830dfef491b3f7da99a14?d=identicon&version=1",
"bot_type": null,
"timezone": "",
"is_bot": false,
"user_id": 7,
"profile_data": {},
"is_guest": false,
"date_joined": "2019-10-20T07:50:53.728864+00:00",
"full_name": "aaron",
},
{
"date_joined": "2019-10-20T07:50:53.729659+00:00",
"full_name": "King Hamlet",
"is_guest": false,
"profile_data":
{
"4": {"value": "vim"},
"2":
{
"value": "I am:\n* The prince of Denmark\n* Nephew to the usurping Claudius",
"rendered_value": "I am:
\n\n- The prince of Denmark
\n- Nephew to the usurping Claudius
\n
",
},
"5": {"value": "1900-1-1"},
"7": {"value": "[11]"},
"6": {"value": "https://blog.zulig.org"},
"1":
{
"value": "+0-11-23-456-7890",
"rendered_value": "+0-11-23-456-7890
",
},
"8": {"value": "zulipbot"},
"3":
{
"rendered_value": "Dark chocolate
",
"value": "Dark chocolate",
},
},
"user_id": 10,
"is_bot": false,
"bot_type": null,
"timezone": "",
"is_admin": false,
"is_owner": false,
"avatar_url": "https://secure.gravatar.com/avatar/6d8cad0fd00256e7b40691d27ddfd466?d=identicon&version=1",
"is_active": true,
"email": "hamlet@zulip.com",
},
{
"bot_owner_id": 11,
"is_guest": false,
"date_joined": "2019-10-20T12:52:17.862053+00:00",
"full_name": "Iago's Bot",
"email": "iago-bot@zulipdev.com",
"is_active": true,
"avatar_url": "https://secure.gravatar.com/avatar/7328586831cdbb1627649bd857b1ee8c?d=identicon&version=1",
"is_admin": false,
"is_owner": false,
"user_id": 23,
"bot_type": 1,
"timezone": "",
"is_bot": true,
},
],
}
post:
operationId: create_user
tags: ["users"]
description: |
{!api-admin-only.md!}
Create a new user account via the API.
`POST {{ api_url }}/v1/users`
parameters:
- name: email
in: query
description: |
The email address of the new user.
schema:
type: string
example: username@example.com
required: true
- name: password
in: query
description: |
The password of the new user.
schema:
type: string
example: abcd1234
required: true
- name: full_name
in: query
description: |
The full name of the new user.
schema:
type: string
example: New User
required: true
responses:
"200":
description: Success.
content:
application/json:
schema:
$ref: "#/components/schemas/JsonSuccess"
"400":
description: Bad request.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonError"
- example:
{
"msg": "Email 'newbie@zulip.com' already in use",
"result": "error",
}
/users/{user_id}/reactivate:
post:
operationId: reactivate_user
tags: ["users"]
description: |
{!api-admin-only.md!}
[Reactivates a
user](https://zulip.com/help/deactivate-or-reactivate-a-user)
given their user ID.
`POST {{ api_url }}/v1/users/{user_id}/reactivate`
parameters:
- $ref: "#/components/parameters/UserId"
responses:
"200":
description: Success
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- example: {"msg": "", "result": "success"}
/users/{email}/presence:
get:
operationId: get_user_presence
tags: ["users"]
description: |
Get the presence status for a specific user.
This endpoint is most useful for embedding data about a user's
presence status in other sites (E.g. an employee directory). Full
Zulip clients like mobile/desktop apps will want to use the main
presence endpoint, which returns data for all active users in the
organization, instead.
`GET {{ api_url }}/v1/users/{email}/presence`
See
[Zulip's developer documentation](https://zulip.readthedocs.io/en/latest/subsystems/presence.html)
for details on the data model for presence in Zulip.
parameters:
- name: email
in: path
description: |
The email address of the user whose presence you want to fetch.
schema:
type: string
example: iago@zulip.com
required: true
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
presence:
type: object
description: |
An object containing the presence details for every client the user has
logged into.
additionalProperties:
type: object
additionalProperties: false
properties:
timestamp:
type: integer
description: |
when this update was received; if the timestamp
is more than a few minutes in the past, the user is offline.
status:
type: string
description: |
either `active` or `idle`: whether the user had
recently interacted with Zulip at the time in the timestamp
(this distinguishes orange vs. green dots in the Zulip web
UI; orange/idle means we don't know whether the user is
actually at their computer or just left the Zulip app open
on their desktop).
description: |
`{client_name}` or `aggregated`: the keys for these objects are
the names of the different clients where this user is logged in,
like `website`, `ZulipDesktop`, `ZulipTerminal`, or
`ZulipMobile`. There is also an `aggregated` key, which matches
the contents of the object that has been updated most
recently. For most applications, you'll just want to look at the
`aggregated` key.
- example:
{
"presence":
{
"website":
{"timestamp": 1532697622, "status": "active"},
"ZulipMobile":
{"timestamp": 1522687421, "status": "active"},
"aggregated":
{"timestamp": 1532697622, "status": "active"},
},
"result": "success",
"msg": "",
}
/users/me:
get:
operationId: get_own_user
tags: ["users"]
description: |
Get basic data about the user/bot that requests this endpoint.
`GET {{ api_url }}/v1/users/me`
responses:
"200":
description: Success
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
avatar_url:
type: string
description: |
URL for the user's avatar.
**Changes**: New in Zulip 2.1.0.
example: "x"
avatar_version:
type: integer
description: |
Version for the the user's avatar. Used for cache-busting requests
for the user's avatar. Clients generally shouldn't need to use this;
most avatar URLs sent by Zulip will already end with `?v={avatar_version}`.
**Changes**: New in Zulip 3.0 (feature level 10). Previous
versions do not return this field.
example: 1
email:
type: string
description: |
Email of the requesting user.
example: "iago@zulip.com"
full_name:
type: string
description: |
Full name of the requesting user.
example: "Iago"
is_admin:
type: boolean
description: |
A boolean indicating if the requesting user is an admin.
example: true
is_owner:
type: boolean
description: |
A boolean indicating if the requesting user is
an organization owner.
**Changes**: New in Zulip 3.0 (feature level 8).
example: false
is_guest:
type: boolean
description: |
A boolean indicating if the requesting user is a guest.
**Changes**: New in Zulip 3.0 (feature level 10). Previous
versions do not return this field.
example: false
is_bot:
type: boolean
description: |
A boolean indicating if the requesting user is a bot.
example: false
is_active:
type: boolean
description: |
A boolean specifying whether the user account has been deactivated.
**Changes**: New in Zulip 3.0 (feature level 10). Previous
versions do not return this field.
example: true
timezone:
type: string
description: |
The time zone of the user.
**Changes**: New in Zulip 3.0 (feature level 10). Previous
versions do not return this field.
example: ""
date_joined:
type: string
description: |
The time the user account was created.
**Changes**: New in Zulip 3.0 (feature level 10). Previous
versions do not return this field.
example: "2019-10-20T07:50:53.728864+00:00"
max_message_id:
type: integer
deprecated: true
description: |
The integer ID of the last message received by your account.
**Deprecated**. We plan to remove this in favor of recommending
using `GET /messages` with `anchor="newest"`.
example: 30
user_id:
type: integer
description: |
The user's ID.
example: 1
delivery_email:
type: string
description: |
The user's real email address. This field is present only if
[email address visibility](/help/restrict-visibility-of-email-addresses) is
limited and you are an administrator with access to real email addresses
under the configured policy.
profile_data:
$ref: "#/components/schemas/profile_data"
- example:
{
"avatar_url": "https://secure.gravatar.com/avatar/af4f06322c177ef4e1e9b2c424986b54?d=identicon&version=1",
"avatar_version": 1,
"email": "iago@zulip.com",
"full_name": "Iago",
"is_admin": true,
"is_owner": false,
"is_guest": false,
"is_bot": false,
"is_active": true,
"timezone": "",
"date_joined": "2019-10-20T07:50:53.728864+00:00",
"max_message_id": 30,
"msg": "",
"result": "success",
"user_id": 5,
"profile_data":
{
"5": {"value": "2000-1-1"},
"4": {"value": "emacs"},
"7": {"value": "[10]"},
"1":
{
"value": "+1-234-567-8901",
"rendered_value": "+1-234-567-8901
",
},
"2":
{
"rendered_value": "Betrayer of Othello.
",
"value": "Betrayer of Othello.",
},
"8": {"value": "zulip"},
"3":
{
"value": "Apples",
"rendered_value": "Apples
",
},
"6":
{
"value": "https://zulip.readthedocs.io/en/latest/",
},
},
}
delete:
operationId: deactivate_my_account
tags: ["users"]
description: |
Delete the requesting user from the realm.
responses:
"200":
description: Bad Request
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- example: {"msg": "", "result": "success"}
"400":
description: Bad Request
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonError"
- example:
{
"msg": "Cannot deactivate the only organization administrator",
"result": "error",
}
/users/me/{stream_id}/topics:
get:
operationId: get_stream_topics
tags: ["streams"]
description: |
Get all the topics in a specific stream
`GET {{ api_url }}/v1/users/me/{stream_id}/topics`
parameters:
- $ref: "#/components/parameters/StreamIdInPath"
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
topics:
type: array
description: |
An array of `topic` objects.
items:
type: object
additionalProperties: false
properties:
max_id:
description: |
The message ID of the last message sent to this topic.
type: integer
name:
description: |
The name of the topic.
type: string
- example:
{
"msg": "",
"result": "success",
"topics":
[
{"max_id": 26, "name": "Denmark3"},
{"max_id": 23, "name": "Denmark1"},
{"max_id": 6, "name": "Denmark2"},
],
}
"400":
description: Bad request.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonError"
- example:
{
"code": "BAD_REQUEST",
"msg": "Invalid stream id",
"result": "error",
}
/users/me/subscriptions:
get:
operationId: get_subscriptions
tags: ["streams"]
description: |
Get all streams that the user is subscribed to.
`GET {{ api_url }}/v1/users/me/subscriptions`
# operationId can be used to record which view function
# corresponds to an endpoint. TODO: Add these for more
# endpoints, and perhaps use this to provide links to implementations.
parameters:
- $ref: "#/components/parameters/IncludeSubscribers"
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
# TODO: Is this the best way to declare required elements in 200 responses?
- required:
- subscriptions
- properties:
subscriptions:
type: array
description: |
A list of dictionaries where each dictionary contains
information about one of the subscribed streams.
items:
$ref: "#/components/schemas/Subscriptions"
- example:
{
"msg": "",
"result": "success",
"subscriptions":
[
{
"audible_notifications": true,
"color": "#e79ab5",
"description": "A Scandinavian country",
"desktop_notifications": true,
"email_address": "Denmark+187b4125ed36d6af8b5d03ef4f65c0cf@zulipdev.com:9981",
"is_muted": false,
"invite_only": false,
"name": "Denmark",
"pin_to_top": false,
"push_notifications": false,
"stream_id": 1,
"subscribers": [7, 10, 11, 12, 14],
},
{
"audible_notifications": true,
"color": "#e79ab5",
"description": "Located in the United Kingdom",
"desktop_notifications": true,
"email_address": "Scotland+f5786390183e60a1ccb18374f9d05649@zulipdev.com:9981",
"is_muted": false,
"invite_only": false,
"name": "Scotland",
"pin_to_top": false,
"push_notifications": false,
"stream_id": 3,
"subscribers": [7, 11, 12, 14],
},
],
}
post:
operationId: subscribe
tags: ["streams"]
description: |
Subscribe one or more users to one or more streams.
`POST {{ api_url }}/v1/users/me/subscriptions`
If any of the specified streams do not exist, they are automatically
created. The initial [stream settings](/api/update-stream) will be determined
by the optional parameters like `invite_only` detailed below.
parameters:
- name: subscriptions
in: query
description: |
A list of dictionaries containing the the key `name` and value
specifying the name of the stream to subscribe. If the stream does not
exist a new stream is created. The description of the stream created can
be specified by setting the dictionary key `description` with an
appropriate value.
content:
application/json:
schema:
type: array
items:
type: object
example: [{"name": "Verona", "description": "Italian City"}]
required: true
- $ref: "#/components/parameters/Principals"
- name: authorization_errors_fatal
in: query
description: |
A boolean specifying whether authorization errors (such as when the
requesting user is not authorized to access a private stream) should be
considered fatal or not. When `True`, an authorization error is reported
as such. When set to `False`, the response will be a 200 and any streams
where the request encountered an authorization error will be listed
in the `unauthorized` key.
schema:
type: boolean
default: true
example: false
- name: announce
in: query
description: |
If one of the streams specified did not exist previously and is thus craeted
by this call, this determines whether [notification bot](/help/configure-notification-bot)
will send an announcement about the new stream's creation.
schema:
type: boolean
default: false
example: true
- name: invite_only
in: query
description: |
As described above, this endpoint will create a new stream if passed
a stream name that doesn't already exist. This parameters and the ones
that follow are used to request an initial configuration of a created
stream; they are ignored for streams that already exist.
This parameter determines whether any newly created streams will be
private streams.
schema:
type: boolean
default: false
example: true
- $ref: "#/components/parameters/HistoryPublicToSubscribers"
- $ref: "#/components/parameters/StreamPostPolicy"
- $ref: "#/components/parameters/MessageRetentionDays"
responses:
"200":
description: Success.
content:
application/json:
schema:
oneOf:
- allOf:
- $ref: "#/components/schemas/AddSubscriptionsResponse"
- example:
{
"already_subscribed": {},
"msg": "",
"result": "success",
"subscribed": {"iago@zulip.com": ["new stream"]},
}
- allOf:
- $ref: "#/components/schemas/AddSubscriptionsResponse"
- example:
{
"already_subscribed":
{"newbie@zulip.com": ["new stream"]},
"msg": "",
"result": "success",
"subscribed": {},
}
"400":
description: Success.
content:
application/json:
schema:
oneOf:
- allOf:
- $ref: "#/components/schemas/AddSubscriptionsResponse"
- example:
{
"msg": "Unable to access stream (private_stream).",
"result": "error",
}
- allOf:
- $ref: "#/components/schemas/AddSubscriptionsResponse"
- example:
{
"already_subscribed": {},
"msg": "",
"result": "success",
"subscribed": {},
"unauthorized": ["private_stream"],
}
patch:
operationId: update_subscriptions
tags: ["streams"]
description: |
Update which streams you are are subscribed to.
parameters:
- name: delete
in: query
description: |
A list of stream names to unsubscribe from.
content:
application/json:
schema:
type: array
items:
type: string
example: ["Verona", "Denmark"]
required: false
- name: add
in: query
description: |
A list of objects describing which streams to subscribe to, optionally
including per-user subscription parameters (e.g. color) and if the
stream is to be created, its description.
content:
application/json:
schema:
type: array
items:
type: object
additionalProperties: false
properties:
name:
type: string
color:
type: string
description:
type: string
example:
[
{"name": "Verona"},
{
"name": "Denmark",
"color": "#e79ab5",
"description": "A Scandinavian country",
},
]
required: false
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- required:
- subscribed
- already_subscribed
- removed
- properties:
subscribed:
type: object
description: |
A dictionary where the key is the email
address of the user/bot and the value is a
list of the names of the streams that were
subscribed to as a result of the query.
additionalProperties:
description: |
`{email_id}`: A list of the names of streams that
the user was subscribed to as a result of the query.
type: array
items:
type: string
already_subscribed:
type: object
description: |
A dictionary where the key is the email
address of the user/bot and the value is a
list of the names of the streams that the
user/bot is already subscribed to.
additionalProperties:
description: |
`{email_id}`: A list of the names of streams that
the user was already subscribed to.
type: array
items:
type: string
not_removed:
type: array
items:
type: string
description: |
A list of the names of streams that the user
is already unsubscribed from, and hence
doesn't need to be unsubscribed.
removed:
type: array
items:
type: string
description: |
A list of the names of streams which were unsubscribed
from as a result of the query.
- example:
{
"msg": "",
"subscribed": {},
"already_subscribed": {"iago@zulip.com": ["Verona"]},
"not_removed": [],
"removed": ["new stream"],
"result": "success",
}
delete:
operationId: unsubscribe
tags: ["streams"]
description: |
Unsubscribe yourself or other users from one or more streams.
`DELETE {{ api_url }}/v1/users/me/subscriptions`
parameters:
- name: subscriptions
in: query
description: |
A list of stream names to unsubscribe from. This parameter is called
`streams` in our Python API.
content:
application/json:
schema:
type: array
items:
type: string
example: ["Verona", "Denmark"]
required: true
- $ref: "#/components/parameters/Principals"
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
not_removed:
type: array
items:
type: string
description: |
A list of the names of streams that the user is already unsubscribed
from, and hence doesn't need to be unsubscribed.
removed:
type: array
items:
type: string
description: |
A list of the names of streams which were unsubscribed from as a result
of the query.
- example:
{
"msg": "",
"not_removed": [],
"removed": ["new stream"],
"result": "success",
}
"400":
description: Bad request.
content:
application/json:
schema:
$ref: "#/components/schemas/NonExistingStreamError"
/users/{user_id}/subscriptions/{stream_id}:
get:
operationId: get_subscription_status
tags: ["streams"]
description: |
Check whether a user is subscribed to a stream.
`GET {{ api_url }}/v1/users/{user_id}/subscriptions/{stream_id}`
**Changes**: New in Zulip 3.0 (feature level 11).
parameters:
- $ref: "#/components/parameters/UserId"
example: 7
- $ref: "#/components/parameters/StreamIdInPath"
example: 1
responses:
"200":
description: Success
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
is_subscribed:
type: boolean
description: |
Whether the user is subscribed to the stream.
- example:
{"msg": "", "result": "success", "is_subscribed": false}
/users/me/subscriptions/muted_topics:
patch:
operationId: mute_topic
tags: ["streams"]
description: |
This endpoint mutes/unmutes a topic within a stream that the current
user is subscribed to. Muted topics are displayed faded in the Zulip
UI, and are not included in the user's unread count totals.
`PATCH {{ api_url }}/v1/users/me/subscriptions/muted_topics`
parameters:
- $ref: "#/components/parameters/Stream"
required: false
- $ref: "#/components/parameters/StreamIdInQuery"
required: false
- name: topic
in: query
description: |
The topic to (un)mute. Note that the request will succeed regardless of
whether any messages have been sent to the specified topic.
schema:
type: string
example: dinner
required: true
- name: op
in: query
description: |
Whether to mute (`add`) or unmute (`remove`) the provided topic.
schema:
type: string
enum:
- add
- remove
example: add
required: true
responses:
"200":
description: Success.
content:
application/json:
schema:
$ref: "#/components/schemas/JsonSuccess"
"400":
description: Bad request.
content:
application/json:
schema:
oneOf:
- allOf:
- $ref: "#/components/schemas/JsonError"
- example:
{"msg": "Topic already muted", "result": "error"}
- allOf:
- $ref: "#/components/schemas/JsonError"
- example:
{"msg": "Topic is not muted", "result": "error"}
/realm/emoji/{emoji_name}:
post:
operationId: upload_custom_emoji
tags: ["server_and_organizations"]
description: |
This endpoint is used to upload a custom emoji for use in the user's
organization. Access to this endpoint depends on the
[organization's configuration](https://zulip.com/help/only-allow-admins-to-add-emoji).
`POST {{ api_url }}/v1/realm/emoji/{emoji_name}`
parameters:
- name: emoji_name
required: true
in: path
description: |
The name that should be associated with the uploaded emoji image/gif.
schema:
type: string
requestBody:
content:
multipart/form-data:
schema:
properties:
filename:
type: string
format: binary
example: /path/to/img.png
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
/realm/emoji:
get:
operationId: get_custom_emoji
tags: ["server_and_organizations"]
description: |
Get all the custom emoji in the user's organization.
`GET {{ api_url }}/v1/realm/emoji`
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
emoji:
type: object
description: |
An object that contains `emoji` objects, each identified with their
emoji ID as the key.
additionalProperties:
type: object
additionalProperties: false
description: |
`{emoji_id}`: Object containing details about the emoji with
the specified ID. It has the following properties:
properties:
id:
type: string
description: |
The ID for this emoji, same as the object's key.
name:
type: string
description: |
The user-friendly name for this emoji. Users in the organization
can use this emoji by writing this name between colons (`:name :`).
source_url:
type: string
description: |
The path relative to the organization's URL where the
emoji's image can be found.
deactivated:
type: boolean
description: |
Whether the emoji has been deactivated or not.
author_id:
type: integer
nullable: true
description: |
The user ID of the user who uploaded the custom emoji.
Will be null if the uploader is unknown.
**Changes**: New in Zulip 3.0 (feature level 7). Previously
was accessible via and `author` object with an `id` field.
- example:
{
"result": "success",
"msg": "",
"emoji":
{
"1":
{
"id": "1",
"name": "green_tick",
"source_url": "/user_avatars/1/emoji/images/1.png",
"deactivated": false,
"author_id": 5,
},
},
}
/users/me/subscriptions/properties:
post:
operationId: update_subscription_settings
tags: ["streams"]
description: |
This endpoint is used to update the user's personal settings for the
streams they are subscribed to, including muting, color, pinning, and
per-stream notification settings.
`POST {{ api_url }}/v1/users/me/subscriptions/properties`
parameters:
- name: subscription_data
in: query
description: |
A list of objects that describe the changes that should be applied in
each subscription. Each object represents a subscription, and must have
a `stream_id` key that identifies the stream, as well as the `property`
being modified and its new `value`.
content:
application/json:
schema:
type: array
items:
type: object
example:
[
{"stream_id": 1, "property": "pin_to_top", "value": true},
{"stream_id": 3, "property": "color", "value": "#f00f00"},
]
required: true
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
subscription_data:
type: array
items:
type: object
additionalProperties: false
properties:
property:
type: string
description: |
The property to be changed. It is one of:
*`color`: The hex value of the user's personal display color for the stream.
*`is_muted`: Whether the stream is [muted](/help/mute-a-stream).
**Changes**: Prior to Zulip 2.1, this feature was
represented by the more confusingly named `in_home_view` (with the
opposite value, `in_home_view=!is_muted`); for
backwards-compatibility, modern Zulip still accepts that value.
*`pin_to_top`: Whether to pin the stream at the top of the stream list.
*`desktop_notifications`: Whether to show desktop notifications for all
messages sent to the stream.
*`audible_notifications`: Whether to play a sound notification for all
messages sent to the stream.
*`push_notifications`: Whether to trigger a mobile push notification for
all messages sent to the stream.
*`email_notifications`: Whether to trigger an email notification for all
messages sent to the stream.
*`in_home_view`: Whether to mute the stream (Legacy property)
*`wildcard_mentions_notify`: whether wildcard mentions trigger notifications
as though they were personal mentions in this stream.
A null value means the value of this setting
should be inherited from the user-level default
setting, wildcard_mentions_notify, for
this stream.
enum:
- color
- push_notifications
- is_muted
- pin_to_top
- desktop_notifications
- audible_notifications
- push_notifications
- email_notifications
- in_home_view
- wildcard_mentions_notify
value:
description: |
The desired value of the property
oneOf:
- type: boolean
- type: string
stream_id:
description: |
The desired value of the property
type: integer
description: |
The same `subscription_data` array sent by the client for the request.
- example:
{
"subscription_data":
[
{
"property": "pin_to_top",
"value": true,
"stream_id": 1,
},
{
"property": "color",
"value": "#f00f00",
"stream_id": 3,
},
],
"result": "success",
"msg": "",
}
/users/{user_id}:
get:
operationId: get_user
tags: ["users"]
description: |
Fetch details for a single user in the organization.
`GET {{ api_url }}/v1/users/{user_id}`
You can also fetch details on [all users in the organization](/api/get-users).
*This endpoint is new in Zulip Server 3.0 (feature level 1).*
parameters:
- $ref: "#/components/parameters/UserId"
- $ref: "#/components/parameters/ClientGravatar"
- $ref: "#/components/parameters/IncludeCustomProfileFields"
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
user:
$ref: "#/components/schemas/User"
- example:
{
"msg": "",
"result": "success",
"user":
{
"date_joined": "2019-10-20T07:50:53.729659+00:00",
"full_name": "King Hamlet",
"is_guest": false,
"profile_data":
{
"4": {"value": "vim"},
"2":
{
"value": "I am:\n* The prince of Denmark\n* Nephew to the usurping Claudius",
"rendered_value": "I am:
\n\n- The prince of Denmark
\n- Nephew to the usurping Claudius
\n
",
},
"5": {"value": "1900-1-1"},
"7": {"value": "[11]"},
"6": {"value": "https://blog.zulig.org"},
"1":
{
"value": "+0-11-23-456-7890",
"rendered_value": "+0-11-23-456-7890
",
},
"8": {"value": "zulipbot"},
"3":
{
"rendered_value": "Dark chocolate
",
"value": "Dark chocolate",
},
},
"user_id": 10,
"is_bot": false,
"bot_type": null,
"timezone": "",
"is_admin": false,
"is_owner": false,
"avatar_url": "https://secure.gravatar.com/avatar/6d8cad0fd00256e7b40691d27ddfd466?d=identicon&version=1",
"is_active": true,
"email": "hamlet@zulip.com",
},
}
patch:
operationId: update_user
tags: ["users"]
description: |
{!api-admin-only.md!}
Administrative endpoint to update the details of another user in the organization.
`PATCH {{ api_url }}/v1/users/{user_id}`
Supports everything an administrator can do to edit details of another
user's account, including editing full name,
[role](/help/roles-and-permissions), and [custom profile
fields](/help/add-custom-profile-fields).
parameters:
- $ref: "#/components/parameters/UserId"
- name: full_name
in: query
description: |
The user's full name.
content:
application/json:
schema:
type: string
example: NewName
required: false
- name: role
in: query
description: |
New [role](/help/roles-and-permissions) for the user. Roles are encoded as:
* Organization owner: 100
* Organization administrator: 200
* Member: 400
* Guest: 600
Only organization owners can add or remove the owner role.
The owner role cannot be removed from the only organization owner.
**Changes**: New in Zulip 3.0 (feature level 8), replacing the previous
pair of `is_admin` and `is_guest` boolean parameters.
schema:
type: integer
example: 400
required: false
- name: profile_data
in: query
description: |
A dictionary containing the to be updated custom profile field data for the user.
content:
application/json:
schema:
type: array
items:
type: object
example:
[{"id": 4, "value": "vim"}, {"id": 5, "value": "1909-04-05"}]
required: false
responses:
"200":
$ref: "#/components/responses/SimpleSuccess"
"400":
description: Bad request.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/CodedError"
- example:
{
"result": "error",
"msg": "Guests cannot be organization administrators",
"code": "BAD_REQUEST",
}
delete:
operationId: deactivate_user
tags: ["users"]
description: |
{!api-admin-only.md!}
[Deactivates a
user](https://zulip.com/help/deactivate-or-reactivate-a-user)
given their user ID.
`DELETE {{ api_url }}/v1/users/{user_id}`
parameters:
- $ref: "#/components/parameters/UserId"
responses:
"200":
description: Success
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- example: {"msg": "", "result": "success"}
"400":
description: Bad Request
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonError"
- example:
{
"msg": "Cannot deactivate the only organization administrator",
"result": "error",
}
/realm/filters:
get:
operationId: get_linkifiers
tags: ["server_and_organizations"]
description: |
List all of an organization's configured
[linkifiers](/help/add-a-custom-linkification-filter), regular
expression patterns that are automatically linkified when they appear
in messages and topics.
`GET {{ api_url }}/v1/realm/filters`
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
filters:
type: array
items:
type: array
items:
oneOf:
- type: string
- type: integer
description: |
An array of tuples, each representing one of
the linkifiers set up in the
organization. Each of these tuples contain the
pattern, the formatted URL and the filter's
ID, in that order. See the [Create
linkifiers](/api/add-linkifier) article for
details on what each field means.
- example:
{
"msg": "",
"filters":
[
[
"#(?P[0-9]+)",
"https://github.com/zulip/zulip/issues/%(id)s",
1,
],
],
"result": "success",
}
post:
operationId: add_linkifier
tags: ["server_and_organizations"]
description: |
Configure [linkifiers](/help/add-a-custom-linkification-filter),
regular expression patterns that are automatically linkified when they
appear in messages and topics.
`POST {{ api_url }}/v1/realm/filters`
parameters:
- name: pattern
in: query
description: |
The [Python regular
expression](https://docs.python.org/3/howto/regex.html) that should
trigger the linkifier.
schema:
type: string
example: "#(?P[0-9]+)"
required: true
- name: url_format_string
in: query
description: |
The URL used for the link. If you used named groups for the `pattern`,
you can insert their content here with
`%(name_of_the_capturing_group)s`.
schema:
type: string
example: https://github.com/zulip/zulip/issues/%(id)s
required: true
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
id:
type: integer
description: |
The numeric ID assigned to this filter.
- example: {"id": 42, "result": "success", "msg": ""}
/realm/filters/{filter_id}:
delete:
operationId: remove_linkifier
tags: ["server_and_organizations"]
description: |
Remove [linkifiers](/help/add-a-custom-linkification-filter), regular
expression patterns that are automatically linkified when they appear
in messages and topics.
`DELETE {{ api_url }}/v1/realm/filters/{filter_id}`
parameters:
- name: filter_id
in: path
description: |
The ID of the filter that you want to remove.
schema:
type: integer
example: 42
required: true
responses:
"200":
description: Success.
content:
application/json:
schema:
$ref: "#/components/schemas/JsonSuccess"
/register:
post:
operationId: register_queue
tags: ["real_time_events"]
description: |
This powerful endpoint can be used to register a Zulip "event queue"
(subscribed to certain types of "events", or updates to the messages and
other Zulip data the current user has access to), as well as to fetch
the current state of that data.
parameters:
- name: apply_markdown
in: query
description: |
Set to `true` if you would like the content to be rendered in HTML
format (otherwise the API will return the raw text that the user
entered)
schema:
type: boolean
default: false
example: true
- $ref: "#/components/parameters/ClientGravatar"
- name: slim_presence
in: query
description: |
Setting this to `true` will make presence dictionaries be keyed by
user_id instead of email.
**Changes**: New in Zulip 3.0 (Unstable with no feature level yet).
schema:
type: boolean
default: false
example: true
- $ref: "#/components/parameters/Event_types"
- name: all_public_streams
in: query
description: |
Set to `True` if you would like to receive events that occur within all
public streams.
schema:
type: boolean
default: false
example: true
- $ref: "#/components/parameters/IncludeSubscribers"
- name: client_capabilities
in: query
description: |
Dictionary containing details on features the client supports that are
relevant to the format of responses sent by the server.
* `notification_settings_null`: Boolean for whether the
client can handle the current API with null values for
stream-level notification settings (which means the stream
is not customized and should inherit the user's global
notification settings for stream messages). New in Zulip
2.1.0; in earlier Zulip releases, stream-level
notification settings were simple booleans.
* `bulk_message_deletion`: Boolean for whether the client's
handler for the `delete_message` event type has been
updated to process the new bulk format (with a
`message_ids`, rather than a singleton `message_id`).
Otherwise, the server will send `delete_message` events
in a loop. New in Zulip 3.0 (feature level 13). This
capability is for backwards-compatibility; it will be
required in a future server release.
* `user_avatar_url_field_optional`: Boolean for whether the
client required avatar URLs for all users, or supports
using `GET /avatar/{user_id}` to access user avatars. If the
client has this capability, the server may skip sending a
`avatar_url` field in the `realm_user` at its sole discretion
to optimize network performance. This is an important optimization
in organizations with 10,000s of users.
New in Zulip 3.0 (feature level 18).
content:
application/json:
schema:
type: object
example: {"notification_settings_null": true}
- name: fetch_event_types
in: query
description: |
Same as the `event_types` parameter except that the values in
`fetch_event_types` are used to fetch initial data. If
`fetch_event_types` is not provided, `event_types` is used and if
`event_types` is not provided, this parameter defaults to `None`.
content:
application/json:
schema:
type: array
items:
type: string
example: ["message"]
- $ref: "#/components/parameters/Narrow"
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
queue_id:
type: string
description: |
The ID of the queue that has been allocated for your client.
last_event_id:
type: integer
description: |
The initial value of `last_event_id` to pass to `GET /api/v1/events`.
zulip_feature_level:
type: integer
description: |
The server's current [Zulip feature level](/api/changelog).
zulip_version:
type: string
description: |
The server's version.
- example:
{
"last_event_id": -1,
"msg": "",
"queue_id": "1517975029:0",
"realm_emoji":
{
"1":
{
"author_id": 5,
"deactivated": false,
"id": "1",
"name": "green_tick",
"source_url": "/user_avatars/1/emoji/images/1.png",
},
},
"result": "success",
"zulip_feature_level": 2,
"zulip_version": "2.1.0",
}
/server_settings:
get:
operationId: get_server_settings
tags: ["server_and_organizations"]
description: |
Fetch global settings for a Zulip server.
`GET {{ api_url }}/v1/server_settings`
**Note:** this endpoint does not require any authentication at all, and you can use it to check:
* If this is a Zulip server, and if so, what version of Zulip it's running.
* What a Zulip client (e.g. a mobile app or
[zulip-terminal](https://github.com/zulip/zulip-terminal/)) needs to
know in order to display a login prompt for the server (e.g. what
authentication methods are available).
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
authentication_methods:
type: object
additionalProperties: false
deprecated: true
description: |
Each key-value pair in the object indicates whether the authentication
method is enabled on this server.
**Changes**: Deprecated in Zulip 2.1, in favor of the more expressive
`external_authentication_methods`.
properties:
password:
description: |
Whether the user can authenticate using password.
type: boolean
dev:
description: |
Whether the user can authenticate using development api key.
type: boolean
email:
description: |
Whether the user can authenticate using email.
type: boolean
ldap:
description: |
Whether the user can authenticate using ldap.
type: boolean
remoteuser:
description: |
Whether the user can authenticate using remoteuser.
type: boolean
github:
description: |
Whether the user can authenticate using their github account.
type: boolean
azuread:
description: |
Whether the user can authenticate using their azuread account.
type: boolean
gitlab:
description: |
Whether the user can authenticate using their gitlab account.
type: boolean
apple:
description: |
Whether the user can authenticate using their apple account.
type: boolean
google:
description: |
Whether the user can authenticate using their google account.
type: boolean
saml:
description: |
Whether the user can authenticate using saml.
type: boolean
external_authentication_methods:
type: array
description: |
A list of dictionaries describing the available external
authentication methods (E.g. Google, GitHub, or SAML)
enabled for this organization.
The list is sorted in the order in which these
authentication methods should be displayed.
**Changes**: New in Zulip 2.1.
items:
type: object
additionalProperties: false
properties:
name:
type: string
description: |
A unique, table, machine-readable name for the authentication method,
intended to be used by clients with special behavior for specific
authenatication methods to correctly identify the method.
display_name:
type: string
description: |
Display name of the authentication method, to be used in all buttons
for the authentication method.
display_icon:
type: string
nullable: true
description: |
URL for an image to be displayed as an icon in all buttons for
the external authentication method.
When null, no icon should be displayed.
login_url:
type: string
description: |
URL to be used to initiate authentication using this method.
signup_url:
type: string
description: |
URL to be used to initiate account registration using this method.
zulip_version:
type: string
description: |
The version of Zulip running in the server.
zulip_feature_level:
type: integer
description: |
An integer indicating what features are
available on the server. The feature level increases monotonically;
a value of N means the server supports all API features introduced
before feature level N. This is designed to provide a simple way
for client apps to decide whether the server supports a given
feature or API change. See the [changelog](/api/changelog) for
details on what each feature level means.
**Changes**. New in Zulip 3.0. We recommend using an implied value
of 0 for Zulip servers that do not send this field.
push_notifications_enabled:
type: boolean
description: |
Whether mobile/push notifications are enabled.
is_incompatible:
type: boolean
description: |
Whether the Zulip client that has sent a request to this endpoint is
deemed incompatible with the server.
email_auth_enabled:
type: boolean
description: |
Setting for allowing users authenticate with an email-password
combination.
require_email_format_usernames:
type: boolean
description: |
Whether all valid usernames for authentication to this
organization will be email addresses. This is important
for clients to know whether to do client side validation
of email address format in a login prompt.
This value will be false if the server has [LDAP
authentication][ldap-auth] enabled with a username and
password combination.
realm_uri:
type: string
description: |
The organization's canonical URL.
realm_name:
type: string
description: |
The organization's name (for display purposes).
realm_icon:
type: string
description: |
The URL for the organization's logo formatted as a square image,
used for identifying the organization in small locations in the
mobile and desktop apps.
realm_description:
type: string
description: |
HTML description of the organization, as configured by the [organization
profile](/help/create-your-organization-profile).
- example:
{
"authentication_methods":
{
"password": true,
"dev": true,
"email": true,
"ldap": false,
"remoteuser": false,
"github": true,
"azuread": false,
"google": true,
"saml": true,
},
"zulip_version": "2.0.6+git",
"push_notifications_enabled": false,
"msg": "",
"is_incompatible": false,
"email_auth_enabled": true,
"require_email_format_usernames": true,
"realm_uri": "http://localhost:9991",
"realm_name": "Zulip Dev",
"realm_icon": "https://secure.gravatar.com/avatar/62429d594b6ffc712f54aee976a18b44?d=identicon",
"realm_description": "The Zulip development environment default organization. It's great for testing!
",
"result": "success",
"external_authentication_methods":
[
{
"name": "saml:idp_name",
"display_name": "SAML",
"display_icon": null,
"login_url": "/accounts/login/social/saml/idp_name",
"signup_url": "/accounts/register/social/saml/idp_name",
},
{
"name": "google",
"display_name": "Google",
"display_icon": "/static/images/landing-page/logos/googl_e-icon.png",
"login_url": "/accounts/login/social/google",
"signup_url": "/accounts/register/social/google",
},
{
"name": "github",
"display_name": "GitHub",
"display_icon": "/static/images/landing-page/logos/github-icon.png",
"login_url": "/accounts/login/social/github",
"signup_url": "/accounts/register/social/github",
},
],
}
/settings/notifications:
patch:
operationId: update_notification_settings
tags: ["users"]
description: |
This endpoint is used to edit the user's global notification settings.
See [this endpoint](/api/update-subscription-settings) for
per-stream notification settings.
`PATCH {{ api_url }}/v1/settings/notifications`
parameters:
- name: enable_stream_desktop_notifications
in: query
description: |
Enable visual desktop notifications for stream messages.
schema:
type: boolean
example: true
- name: enable_stream_email_notifications
in: query
description: |
Enable email notifications for stream messages.
schema:
type: boolean
example: true
- name: enable_stream_push_notifications
in: query
description: |
Enable mobile notifications for stream messages.
schema:
type: boolean
example: true
- name: enable_stream_audible_notifications
in: query
description: |
Enable audible desktop notifications for stream messages.
schema:
type: boolean
example: true
- name: notification_sound
in: query
description: |
Notification sound name.
content:
application/json:
schema:
type: string
example: ding
- name: enable_desktop_notifications
in: query
description: |
Enable visual desktop notifications for private messages and @-mentions.
schema:
type: boolean
example: true
- name: enable_sounds
in: query
description: |
Enable audible desktop notifications for private messages and
@-mentions.
schema:
type: boolean
example: true
- name: enable_offline_email_notifications
in: query
description: |
Enable email notifications for private messages and @-mentions received
when the user is offline.
schema:
type: boolean
example: true
- name: enable_offline_push_notifications
in: query
description: |
Enable mobile notification for private messages and @-mentions received
when the user is offline.
schema:
type: boolean
example: true
- name: enable_online_push_notifications
in: query
description: |
Enable mobile notification for private messages and @-mentions received
when the user is online.
schema:
type: boolean
example: true
- name: enable_digest_emails
in: query
description: |
Enable digest emails when the user is away.
schema:
type: boolean
example: true
- name: enable_login_emails
in: query
description: |
Enable email notifications for new logins to account.
schema:
type: boolean
example: true
- name: message_content_in_email_notifications
in: query
description: |
Include the message's content in missed messages email notifications.
schema:
type: boolean
example: true
- name: pm_content_in_desktop_notifications
in: query
description: |
Include content of private messages in desktop notifications.
schema:
type: boolean
example: true
- name: wildcard_mentions_notify
in: query
description: |
Whether wildcard mentions (E.g. @**all**) should send notifications
like a personal mention.
schema:
type: boolean
example: true
- name: desktop_icon_count_display
in: query
description: |
Unread count summary (appears in desktop sidebar and browser tab)
* 1 - All unreads
* 2 - Private messages and mentions
* 3 - None
content:
application/json:
schema:
type: integer
enum:
- 1
- 2
- 3
example: 1
- name: realm_name_in_notifications
in: query
description: |
Include organization name in subject of missed message emails.
schema:
type: boolean
example: true
- name: presence_enabled
in: query
description: |
Display the presence status to other users when online.
schema:
type: boolean
example: true
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
enable_desktop_notifications:
type: boolean
description: |
The setting for `enable_desktop_notifications`, if it was changed in
this request.
enable_digest_emails:
type: boolean
description: |
The setting for `enable_digest_emails`, if it was changed in this
request.
enable_offline_email_notifications:
type: boolean
description: |
The setting for `enable_offline_email_notifications`, if it was changed
in this request.
enable_offline_push_notifications:
type: boolean
description: |
The setting for `enable_offline_push_notifications`, if it was changed
in this request.
enable_online_push_notifications:
type: boolean
description: |
The setting for `enable_online_push_notifications`, if it was changed in
this request.
enable_sounds:
type: boolean
description: |
The setting for `enable_sounds`, if it was changed in this request.
enable_stream_email_notifications:
type: boolean
description: |
The setting for `enable_stream_email_notifications`, if it was changed
in this request.
enable_stream_push_notifications:
type: boolean
description: |
The setting for `enable_stream_push_notifications`, if it was changed in
this request.
enable_stream_audible_notifications:
type: boolean
description: |
The setting for `enable_stream_audible_notifications`, if it was changed
in this request.
message_content_in_email_notifications:
type: boolean
description: |
The setting for `message_content_in_email_notifications`, if it was
changed in this request.
- example:
{
"enable_offline_push_notifications": true,
"enable_online_push_notifications": true,
"msg": "",
"result": "success",
}
/streams:
get:
operationId: get_streams
tags: ["streams"]
description: |
Get all streams that the user has access to.
`GET {{ api_url }}/v1/streams`
parameters:
- name: include_public
in: query
description: |
Include all public streams.
schema:
type: boolean
default: true
example: false
- name: include_subscribed
in: query
description: |
Include all streams that the user is subscribed to.
schema:
type: boolean
default: true
example: false
- name: include_all_active
in: query
description: |
Include all active streams. The user must have administrative privileges
to use this parameter.
schema:
type: boolean
default: false
example: true
- name: include_default
in: query
description: |
Include all default streams for the user's realm.
schema:
type: boolean
default: false
example: true
- name: include_owner_subscribed
in: query
description: |
If the user is a bot, include all streams that the bot's owner is
subscribed to.
schema:
type: boolean
default: false
example: true
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
streams:
description: |
A list of `stream` objects with details on the requested streams.
type: array
items:
allOf:
- $ref: "#/components/schemas/BasicStream"
- properties:
is_default:
type: boolean
description: |
Whether the given stream is a
[default stream](/help/set-default-streams-for-new-users). Only
returned if the `include_default` parameter is `true`.
- example:
{
"msg": "",
"result": "success",
"streams":
[
{
"description": "A Scandinavian country",
"invite_only": false,
"name": "Denmark",
"stream_id": 1,
},
{
"description": "Yet another Italian city",
"invite_only": false,
"name": "Rome",
"stream_id": 2,
},
{
"description": "Located in the United Kingdom",
"invite_only": false,
"name": "Scotland",
"stream_id": 3,
},
{
"description": "A northeastern Italian city",
"invite_only": false,
"name": "Venice",
"stream_id": 4,
},
{
"description": "A city in Italy",
"invite_only": false,
"name": "Verona",
"stream_id": 5,
},
{
"description": "New stream for testing",
"invite_only": false,
"name": "new stream",
"stream_id": 6,
},
],
}
"400":
description: Bad request.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/CodedError"
- example:
{
"code": "BAD_REQUEST",
"msg": "User not authorized for this query",
"result": "error",
}
/streams/{stream_id}:
delete:
operationId: delete_stream
tags: ["streams"]
description: |
[Delete the stream](/help/delete-a-stream) with the ID `stream_id`.
`DELETE {{ api_url }}/v1/streams/{stream_id}`
parameters:
- $ref: "#/components/parameters/StreamIdInPath"
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- example: {"msg": "", "result": "success"}
"400":
description: Bad request.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonError"
- properties:
msg:
type: string
- example:
{
"code": "BAD_REQUEST",
"msg": "Invalid stream id",
"result": "error",
}
patch:
operationId: update_stream
tags: ["streams"]
description: |
Configure the stream with the ID `stream_id`. This endpoint supports
an organization administrator editing any property of a stream,
including:
* Stream [name](/help/rename-a-stream) and [description](/help/change-the-stream-description)
* Stream [permissions](/help/stream-permissions), including
[privacy](/help/change-the-privacy-of-a-stream) and [who can
send](/help/stream-sending-policy).
`PATCH {{ api_url }}/v1/streams/{stream_id}`
parameters:
- $ref: "#/components/parameters/StreamIdInPath"
- name: description
in: query
description: |
The new description for the stream.
content:
application/json:
schema:
type: string
example: This stream is related to football dicsussions.
required: false
- name: new_name
in: query
description: |
The new name for the stream.
content:
application/json:
schema:
type: string
example: Italy
required: false
- name: is_private
in: query
description: |
Change whether the stream is a private stream.
schema:
type: boolean
example: true
required: false
- name: is_announcement_only
in: query
deprecated: true
description: |
Whether the stream is limited to announcements.
**Changes**: Deprecated in Zulip 3.0 (feature level 1), use
`stream_post_policy` instead.
schema:
type: boolean
example: true
required: false
- $ref: "#/components/parameters/StreamPostPolicy"
- $ref: "#/components/parameters/HistoryPublicToSubscribers"
- $ref: "#/components/parameters/MessageRetentionDays"
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- example: {"msg": "", "result": "success"}
"400":
description: Bad request.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonError"
- example:
{
"code": "BAD_REQUEST",
"msg": "Invalid stream id",
"result": "error",
}
/typing:
post:
operationId: set_typing_status
tags: ["users"]
description: |
Send an event indicating that the user has started or stopped typing
on their client. See
[the typing notification docs](https://zulip.readthedocs.io/en/latest/subsystems/typing-indicators.html)
for details on Zulip's typing notifications protocol.
`POST {{ api_url }}/v1/typing`
parameters:
- name: op
in: query
description: |
Whether the user has started (`start`) or stopped (`stop`) to type.
schema:
type: string
enum:
- start
- stop
example: start
required: true
- name: to
in: query
description: |
The user_ids of the recipients of the message being typed. Typing
notifications are only supported for private messages. Send a
JSON-encoded list of user_ids. (Use a list even if there is only one
recipient.).
**Changes**: Before Zulip 2.0, this parameter accepted only a JSON-encoded
list of email addresses. Support for the email address-based format was
removed in Zulip 3.0 (feature level 11).
content:
application/json:
schema:
type: array
items:
type: integer
example: [9, 10]
required: true
responses:
"200":
description: Success.
content:
application/json:
schema:
$ref: "#/components/schemas/JsonSuccess"
/user_groups/create:
post:
operationId: create_user_group
tags: ["users"]
description: |
Create a new [user group](/help/user-groups).
`POST {{ api_url }}/v1/user_groups/create`
parameters:
- name: name
in: query
description: |
The name of the user group.
schema:
type: string
example: marketing
required: true
- name: description
in: query
description: |
The description of the user group.
schema:
type: string
example: The marketing team.
required: true
- name: members
in: query
description: |
An array containing the user IDs of the initial members for the
new user group.
content:
application/json:
schema:
type: array
items:
type: integer
example: [1, 2, 3, 4]
required: true
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- example: {"msg": "", "result": "success"}
"400":
description: Bad request.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonError"
- example:
{
"result": "error",
"code": "BAD_REQUEST",
"msg": "Invalid user ID: 500",
}
/user_groups/{group_id}:
patch:
operationId: update_user_group
tags: ["users"]
description: |
Update the name or description of a [user group](/help/user-groups).
`PATCH {{ api_url }}/v1/user_groups/{group_id}`
parameters:
- $ref: "#/components/parameters/GroupId"
- name: name
in: query
description: |
The new name of the group.
schema:
type: string
example: marketing team
required: true
- name: description
in: query
description: |
The new description of the group.
schema:
type: string
example: The marketing team.
required: true
responses:
"200":
$ref: "#/components/responses/SimpleSuccess"
"400":
description: Bad request.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonError"
- example:
{
"code": "BAD_REQUEST",
"msg": "Invalid user group",
"result": "error",
}
delete:
operationId: remove_user_group
tags: ["users"]
description: |
Delete a [user group](/help/user-groups).
`DELETE {{ api_url }}/v1/user_groups/{group_id}`
parameters:
- $ref: "#/components/parameters/GroupId"
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- example: {"result": "success", "msg": ""}
"400":
description: Bad request.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonError"
- example:
{
"code": "BAD_REQUEST",
"msg": "Invalid user group",
"result": "error",
}
/user_groups:
get:
operationId: get_user_groups
tags: ["users"]
description: |
Fetches all of the user groups in the organization.
`GET {{ api_url }}/v1/user_groups`
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
user_groups:
type: array
items:
type: object
additionalProperties: false
properties:
description:
type: string
description: |
The human-readable description of the user group.
id:
type: integer
description: |
The user group's integer id.
members:
type: array
description: |
The integer User IDs of the user group members.
items:
type: integer
name:
type: string
description: |
User group name.
description: |
A list of `user_group` objects, which contain a `description`, a `name`,
their `id` and the list of members of the user group.
- example:
{
"msg": "",
"result": "success",
"user_groups":
[
{
"description": "Characters of Hamlet",
"id": 1,
"name": "hamletcharacters",
"members": [3, 4],
},
{
"description": "Other users",
"id": 2,
"name": "other users",
"members": [1, 2],
},
],
}
/real-time:
# This entry is a hack; it exists to give us a place to put the text
# documenting the parameters for call_on_each_event and friends.
post:
tags: ["real_time_events"]
description: |
(Ignored)
parameters:
- $ref: "#/components/parameters/Narrow"
- $ref: "#/components/parameters/Event_types"
security:
- basicAuth: []
responses:
# Makeshift response for this hack entry.
"200":
description: Success
/rest-error-handling:
post:
operationId: rest_error_handling
tags: ["real_time_events"]
description: |
Common error to many endpoints
responses:
"400":
description: |
Bad request.
content:
application/json:
schema:
oneOf:
- allOf:
- $ref: "#/components/schemas/InvalidApiKeyError"
- allOf:
- $ref: "#/components/schemas/MissingArgumentError"
- allOf:
- $ref: "#/components/schemas/UserNotAuthorizedError"
/zulip-outgoing-webhook:
post:
operationId: zulip_outgoing_webhooks
tags: ["webhooks"]
description: |
Outgoing Webhooks allows to build or set up Zulip integrations which are
notified when certain types of messages are sent in Zulip.
responses:
"200":
description: |
Success
content:
application/json:
schema:
additionalProperties: false
properties:
data:
type: string
description: |
The message content, in raw markdown format (not rendered to HTML).
trigger:
type: string
description: |
What aspect of the message triggered the outgoing webhook notification.
Possible values include `private_message` and `mention`.
token:
type: string
description: |
A string of alphanumeric characters that can be use to authenticate the
webhook request. You can get the token used by a given outgoing webhook bot
in the `zuliprc` file downloaded when creating the bot.
message:
allOf:
- description: |
A dict containing details on the message that triggered the
outgoing webhook, in the format used by [`GET /messages`](/api/get-messages).
- $ref: "#/components/schemas/Messages"
- properties:
rendered_content:
type: string
description: |
The content/body of the message rendered in HTML.
bot_email:
type: string
description: |
Email of the bot user.
example:
{
"data": "@**Outgoing Webhook Test** Zulip is the world\u2019s most productive group chat!",
"trigger": "mention",
"token": "xvOzfurIutdRRVLzpXrIIHXJvNfaJLJ0",
"message":
{
"subject": "Verona2",
"sender_email": "iago@zulip.com",
"timestamp": 1527876931,
"client": "website",
"submessages": [],
"recipient_id": 20,
"topic_links": [],
"sender_full_name": "Iago",
"avatar_url": "https://secure.gravatar.com/avatar/1f4f1575bf002ae562fea8fc4b861b09?d=identicon&version=1",
"rendered_content": "@Outgoing Webhook Test Zulip is the world\u2019s most productive group chat!
",
"sender_id": 5,
"stream_id": 5,
"content": "@**Outgoing Webhook Test** Zulip is the world\u2019s most productive group chat!",
"display_recipient": "Verona",
"type": "stream",
"id": 112,
"is_me_message": false,
"reactions": [],
"sender_realm_str": "zulip",
},
"bot_email": "outgoing-bot@localhost",
}
/calls/bigbluebutton/create:
get:
tags: ["streams"]
operationId: create_big_blue_button_video_call
description: |
Create a video call url for a Big Blue Button video call.
Requires Big Blue Button to be configured on the Zulip server.
responses:
"200":
description: Success.
content:
application/json:
schema:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
url:
description: |
The url for the Big Blue Button video call.
type: string
example: "/calls/bbb/join?meeting_id=%22zulip-something%22&password=%22something%22&checksum=%22somechecksum%22"
- example:
{
"msg": "",
"result": "success",
"url": "/calls/bbb/join?meeting_id=%22zulip-something%22&password=%22something%22&checksum=%22somechecksum%22",
}
components:
#######################
# Security definitions
#######################
securitySchemes:
BasicAuth:
type: http
scheme: basic
description: |
Basic authentication, with the user's email as the username, and the API
key as the password. The API key can be fetched using the
`/fetch_api_key` or `/dev_fetch_api_key` endpoints.
schemas:
BasicStream:
type: object
additionalProperties: false
properties:
stream_id:
type: integer
description: |
The unique ID of the stream.
name:
type: string
description: |
The name of the stream.
description:
type: string
description: |
The short description of the stream in text/markdown format,
intended to be used to prepopulate UI for editing a stream's
description.
date_created:
type: integer
description: |
The UNIX timestamp for when the stream was created, in UTC seconds.
**Changes**: New in Zulip 4.0 (feature level 30).
invite_only:
type: boolean
description: |
Specifies whether the stream is private or not.
Only people who have been invited can access a private stream.
rendered_description:
type: string
description: |
The short description of the stream rendered as HTML, intended to
be used when displaying the stream description in a UI.
One should use the standard Zulip rendered_markdown CSS when
displaying this content so that emoji, LaTeX, and other syntax
work correctly. And any client-side security logic for
user-generated message content should be applied when displaying
this HTML as though it were the body of a Zulip message.
is_web_public:
type: boolean
description: |
Whether the stream has been configured to allow unauthenticated
access to its message history from the web.
stream_post_policy:
type: integer
description: |
Policy for which users can post messages to the stream.
* 1 => Any user can post.
* 2 => Only administrators can post.
* 3 => Only new members can post.
**Changes**: New in Zulip 3.0, replacing the previous
`is_announcement_only` boolean.
message_retention_days:
type: integer
nullable: true
description: |
Number of days that messages sent to this stream will be stored
before being automatically deleted by the [message retention
policy](/help/message-retention-policy). There are two special values:
* `null`, the default, means the stream will inherit the organization
level setting.
* `-1` encodes retaining messages in this stream forever.
**Changes**: New in Zulip 3.0 (feature level 17).
history_public_to_subscribers:
type: boolean
description: |
Whether the history of the stream is public to its subscribers.
Currently always true for public streams (i.e. invite_only=False implies
history_public_to_subscribers=True), but clients should not make that
assumption, as we may change that behavior in the future.
first_message_id:
type: integer
nullable: true
description: |
The id of the first message in the stream.
Intended to help clients determine whether they need to display
UI like the "more topics" widget that would suggest the stream
has older history that can be accessed.
Null is used for streams with no message history.
is_announcement_only:
type: boolean
deprecated: true
description: |
Whether the given stream is announcement only or not.
**Changes**: Deprecated in Zulip 3.0 (feature level 1), use
`stream_post_policy` instead.
Subscriptions:
type: object
additionalProperties: false
properties:
stream_id:
type: integer
description: |
The unique ID of a stream.
name:
type: string
description: |
The name of a stream.
description:
type: string
description: |
The short description of a stream in text/markdown format,
intended to be used to prepopulate UI for editing a stream's
description.
rendered_description:
type: string
description: |
A short description of a stream rendered as HTML, intended to
be used when displaying the stream description in a UI.
One should use the standard Zulip rendered_markdown CSS when
displaying this content so that emoji, LaTeX, and other syntax
work correctly. And any client-side security logic for
user-generated message content should be applied when displaying
this HTML as though it were the body of a Zulip message.
date_created:
type: integer
description: |
The UNIX timestamp for when the stream was created, in UTC seconds.
**Changes**: New in Zulip 4.0 (feature level 30).
invite_only:
type: boolean
description: |
Specifies whether the stream is private or not.
Only people who have been invited can access a private stream.
# TODO: This subscribers item should probably be declared optional more
# explicitly in the OpenAPI format?
subscribers:
type: array
items:
type: integer
description: |
A list of user IDs of users who are also subscribed
to a given stream. Included only if `include_subscribers` is `true`.
desktop_notifications:
type: boolean
nullable: true
description: |
A boolean specifying whether desktop notifications
are enabled for the given stream.
A null value means the value of this setting
should be inherited from the user-level default
setting, enable_stream_desktop_notifications, for
this stream.
email_notifications:
type: boolean
nullable: true
description: |
A boolean specifying whether email notifications
are enabled for the given stream.
A null value means the value of this setting
should be inherited from the user-level default
setting, enable_stream_email_notifications, for
this stream.
wildcard_mentions_notify:
type: boolean
nullable: true
description: |
A boolean specifying whether wildcard mentions
trigger notifications as though they were personal
mentions in this stream.
A null value means the value of this setting
should be inherited from the user-level default
setting, wildcard_mentions_notify, for
this stream.
push_notifications:
type: boolean
nullable: true
description: |
A boolean specifying whether push notifications
are enabled for the given stream.
A null value means the value of this setting
should be inherited from the user-level default
setting, enable_stream_push_notifications, for
this stream.
audible_notifications:
type: boolean
nullable: true
description: |
A boolean specifying whether audible notifications
are enabled for the given stream.
A null value means the value of this setting
should be inherited from the user-level default
setting, enable_stream_audible_notifications, for
this stream.
pin_to_top:
type: boolean
description: |
A boolean specifying whether the given stream has been pinned
to the top.
email_address:
type: string
description: |
Email address of the given stream, used for
[sending emails to the stream](/help/message-a-stream-by-email).
is_muted:
type: boolean
description: |
Whether the user has muted the stream. Muted streams do
not count towards your total unread count and do not show up in
`All messages` view (previously known as `Home` view).
**Changes**: Prior to Zulip 2.1, this feature was
represented by the more confusingly named `in_home_view` (with the
opposite value, `in_home_view=!is_muted`).
in_home_view:
type: boolean
deprecated: true
description: |
Legacy property for if the given stream is muted, with inverted meeting.
**Deprecated**; clients should use is_muted where available.
is_announcement_only:
type: boolean
deprecated: true
description: |
Whether only organization administrators can post to the stream.
**Changes**: Deprecated in Zulip 3.0 (feature level 1), use
`stream_post_policy` instead.
is_web_public:
type: boolean
description: |
Whether the stream has been configured to allow unauthenticated
access to its message history from the web.
color:
type: string
description: |
The user's personal color for the stream.
stream_post_policy:
type: integer
description: |
Policy for which users can post messages to the stream.
* 1 => Any user can post.
* 2 => Only administrators can post.
* 3 => Only new members can post.
**Changes**: New in Zulip 3.0, replacing the previous
`is_announcement_only` boolean.
message_retention_days:
type: integer
nullable: true
description: |
Number of days that messages sent to this stream will be stored
before being automatically deleted by the [message retention
policy](/help/message-retention-policy). There are two special values:
* `null`, the default, means the stream will inherit the organization
level setting.
* `-1` encodes retaining messages in this stream forever.
**Changes**: New in Zulip 3.0 (feature level 17).
history_public_to_subscribers:
type: boolean
description: |
Whether the history of the stream is public to its subscribers.
Currently always true for public streams (i.e. invite_only=False implies
history_public_to_subscribers=True), but clients should not make that
assumption, as we may change that behavior in the future.
first_message_id:
type: integer
nullable: true
description: |
The id of the first message in the stream.
Intended to help clients determine whether they need to display
UI like the "more topics" widget that would suggest the stream
has older history that can be accessed.
Null is used for streams with no message history.
stream_weekly_traffic:
type: integer
nullable: true
description: |
The average number of messages sent to the stream in recent weeks,
rounded to the nearest integer.
Null means the stream was recently created and there is
insufficient data to estimate the average traffic.
EmojiReaction:
type: object
additionalProperties: false
properties:
emoji_code:
type: string
description: |
A unique identifier, defining the specific emoji codepoint requested,
within the namespace of the `reaction_type`.
For example, for `unicode_emoji`, this will be an encoding of the
unicode codepoint.
emoji_name:
type: string
description: |
Name of the emoji.
reaction_type:
type: string
description: |
One of the following values:
* `unicode_emoji`: Unicode emoji (`emoji_code` will be its unicode
codepoint).
* `realm_emoji`: [Custom emoji](/help/add-custom-emoji).
(`emoji_code` will be its ID).
* `zulip_extra_emoji`: Special emoji included with Zulip. Exists to
namespace the `zulip` emoji.
user_id:
type: integer
description: |
The ID of the user who added the reaction.
**Changes**: New in Zulip 3.0 (feature level 2). The `user`
object is deprecated and will be removed in the future.
user:
type: object
additionalProperties: false
deprecated: true
description: |
Dictionary with data on the user who added the reaction, including
the user ID as the `id` field. **Note**: In the [events
API](/api/get-events), this `user` dictionary
confusing had the user ID in a field called `user_id`
instead. We recommend ignoring fields other than the user
ID. **Deprecated** and to be removed in a future release
once core clients have migrated to use the `user_id` field.
properties:
id:
type: integer
description: |
ID of the user.
email:
type: string
description: |
Email of the user.
full_name:
type: string
description: |
Full name of the user.
is_mirror_dummy:
type: boolean
description: |
Whether the user is a mirror dummy.
Messages:
type: object
description: |
Object containing details of the message.
additionalProperties: false
properties:
avatar_url:
type: string
nullable: true
description: |
The URL of the user's avatar. Can be null only if client_gravatar was passed,
which means that the user has not uploaded an avatar in Zulip, and the
client should compute the gravatar URL by hashing the
user's email address itself for this user.
client:
type: string
description: |
A Zulip "client" string, describing what Zulip client
sent the message.
content:
type: string
description: |
The content/body of the message.
content_type:
type: string
description: |
The HTTP `content_type` for the message content. This
will be `text/html` or `text/x-markdown`, depending on
whether `apply_markdown` was set.
display_recipient:
oneOf:
- type: string
- type: array
items:
type: object
additionalProperties: false
properties:
id:
type: integer
description: |
ID of the user.
email:
type: string
description: |
Email of the user.
full_name:
type: string
description: |
Full name of the user.
is_mirror_dummy:
type: boolean
description: |
Whether the user is a mirror dummy.
description: |
Data on the recipient of the message;
either the name of a stream or a dictionary containing basic data on
the users who received the message.
id:
type: integer
description: |
The unique message ID. Messages should always be
displayed sorted by ID.
is_me_message:
type: boolean
description: |
Whether the message is a [/me status message][status-messages]
reactions:
type: array
description: |
Data on any reactions to the message.
items:
$ref: "#/components/schemas/EmojiReaction"
recipient_id:
type: integer
description: |
A unique ID for the set of users receiving the
message (either a stream or group of users). Useful primarily
for hashing.
sender_email:
type: string
description: |
The Zulip display email address of the message's sender.
sender_full_name:
type: string
description: |
The full name of the message's sender.
sender_id:
type: integer
description: |
The user ID of the message's sender.
sender_realm_str:
type: string
description: |
A string identifier for the realm the sender is in. Unique only within
the context of a given Zulip server.
E.g. on `example.zulip.com`, this will be `example`.
stream_id:
type: integer
description: |
Only present for stream messages; the ID of the stream.
subject:
type: string
description: |
The `topic` of the message (only present for stream
messages). The field name is a legacy holdover from when topics were
called "subjects" and will eventually change.
topic_links:
type: array
items:
type: string
description: |
Data on any links to be included in the `topic`
line (these are generated by [custom linkification
filters][linkification-filters] that match content in the
message's topic.)
**Changes**: New in Zulip 3.0 (feature level 1).
Previously, this field was called `subject_links`;
clients are recommended to rename `subject_links`
to `topic_links` if present for compatibility with
older Zulip servers.
submessages:
type: array
items:
type: string
description: |
Data used for certain experimental Zulip integrations.
timestamp:
type: integer
description: |
The UNIX timestamp for when the message was sent,
in UTC seconds.
type:
type: string
description: |
The type of the message: `stream` or `private`.
GetMessages:
allOf:
- $ref: "#/components/schemas/Messages"
- properties:
flags:
type: array
description: |
The user's [message flags][message-flags] for the message.
items:
type: string
last_edit_timestamp:
type: integer
description: |
The UNIX timestamp for when the message was last edited,
in UTC seconds.
match_content:
type: string
description: |
Only present if keyword search was included among the narrow parameters.
HTML content of a queried message that matches the narrow, with
`` elements wrapping the matches for the
search keywords.
match_subject:
type: string
description: |
Only present if keyword search was included among the narrow parameters.
HTML-escaped topic of a queried message that matches the narrow, with
`` elements wrapping the matches for the
search keywords.
User:
type: object
additionalProperties: false
description: |
A dictionary containing basic data on a given Zulip user.
properties:
email:
type: string
description: |
The Zulip API email address of the user or bot.
If you do not have permission to view the email address of the target user,
this will be a fake email address that is usable for the Zulip API but nothing else.
is_bot:
type: boolean
description: |
A boolean specifying whether the user is a bot or full account.
avatar_url:
type: string
nullable: true
description: |
URL for the the user's avatar. Will be `null` if the `client_gravatar`
query parameter was set to `True` and the user's avatar is hosted by
the Gravatar provider (i.e. the user has never uploaded an avatar).
avatar_version:
type: integer
description: |
Version for the the user's avatar. Used for cache-busting requests
for the user's avatar. Clients generally shouldn't need to use this;
most avatar URLs sent by Zulip will already end with `?v={avatar_version}`.
full_name:
type: string
description: |
Full name of the user or bot, used for all display purposes.
is_admin:
type: boolean
description: |
A boolean specifying whether the user is an organization administrator.
is_owner:
type: boolean
description: |
A boolean specifying whether the user is an organization owner.
If true, is_admin will also be true.
**Changes**: New in Zulip 3.0 (feature level 8).
bot_type:
type: integer
nullable: true
description: |
An integer describing the type of bot:
* `null` if the user isn't a bot.
* `1` for a `Generic` bot.
* `2` for an `Incoming webhook` bot.
* `3` for an `Outgoing webhook` bot.
* `4` for an `Embedded` bot.
user_id:
type: integer
description: |
The unique ID of the user.
bot_owner_id:
type: integer
nullable: true
description: |
If the user is a bot (i.e. `is_bot` is `True`),
`bot_owner` is the user ID of the bot's owner (usually, whoever
created the bot).
Will be null for legacy bots that do not have an owner.
**Changes**: New in Zulip 3.0 (feature level
1). In previous versions, there was a `bot_owner` field
containing the email address of the bot's owner.
is_active:
type: boolean
description: |
A boolean specifying whether the user account has been deactivated.
is_guest:
type: boolean
description: |
A boolean specifying whether the user is a guest user.
timezone:
type: string
description: |
The time zone of the user.
date_joined:
type: string
description: |
The time the user account was created.
delivery_email:
type: string
description: |
The user's real email address. This field is present only if
[email address visibility](/help/restrict-visibility-of-email-addresses) is
limited and you are an administrator with access to real email addresses
under the configured policy.
profile_data:
$ref: "#/components/schemas/profile_data"
profile_data:
type: object
description: |
A dictionary containing custom profile field data for the user. Each entry
maps the integer ID of a custom profile field in the organization to a
dictionary containing the user's data for that field. Generally the data
includes just a single `value` key; for those custom profile fields
supporting markdown, a `rendered_value` key will also be present.
additionalProperties:
type: object
additionalProperties: false
description: |
'{id}': Object with data about what value user filled in the custom
profile field with id `id`.
properties:
value:
type: string
description: |
User's personal value for this custom profile field.
rendered_value:
type: string
description: |
The `value` rendered in HTML. Will only be present for
custom profile field types that support markdown rendering.
This user-generated HTML content should be rendered
using the same CSS and client-side security protections
as are used for message content.
JsonResponse:
type: object
additionalProperties: false
properties:
result:
type: string
JsonSuccess:
allOf:
- $ref: "#/components/schemas/JsonResponse"
- required:
- result
- msg
- properties:
result:
enum:
- success
msg:
type: string
- example: {"msg": "", "result": "success"}
JsonError:
allOf:
- $ref: "#/components/schemas/JsonResponse"
- required:
- result
- msg
- properties:
result:
enum:
- error
msg:
type: string
ApiKeyResponse:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- required:
- api_key
- email
- properties:
api_key:
type: string
description: |
The API key that can be used to authenticate as the requested user.
email:
type: string
description: |
The email address of the user who owns the API key
- example:
{
"api_key": "gjA04ZYcqXKalvYMA8OeXSfzUOLrtbZv",
"email": "iago@zulip.com",
"msg": "",
"result": "success",
}
CodedError:
allOf:
- $ref: "#/components/schemas/JsonError"
- properties:
code:
type: string
description: |
A string that identifies the error.
BadEventQueueIdError:
allOf:
- $ref: "#/components/schemas/CodedError"
- properties:
queue_id:
type: string
description: |
The string that identifies the invalid event queue.
- example:
{
"code": "BAD_EVENT_QUEUE_ID",
"msg": "Bad event queue id: 1518820930:1",
"queue_id": "1518820930:1",
"result": "error",
}
InvalidMessageError:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
raw_content:
type: string
description: |
The raw content of the message.
- example:
{
"msg": "Invalid message(s)",
"code": "BAD_REQUEST",
"result": "error",
}
NonExistingStreamError:
allOf:
- $ref: "#/components/schemas/CodedError"
- properties:
stream:
type: string
description: |
The name of the stream that could not be found.
- example:
{
"code": "STREAM_DOES_NOT_EXIST",
"msg": "Stream 'nonexistent_stream' does not exist",
"result": "error",
"stream": "nonexistent_stream",
}
AddSubscriptionsResponse:
allOf:
- $ref: "#/components/schemas/JsonSuccess"
- properties:
subscribed:
type: object
description: |
A dictionary where the key is the email address of the user/bot and the
value is a list of the names of the streams that were subscribed to as a
result of the query.
additionalProperties:
description: |
`{email_address}`: List of the names of the streams that were subscribed
to as a result of the query.
type: array
items:
type: string
already_subscribed:
type: object
description: |
A dictionary where the key is the email address of the user/bot and the
value is a list of the names of the streams that the user/bot is already
subscribed to.
additionalProperties:
description: |
{email_address}`: List of the names of the streams that the user is
already subscribed to.
type: array
items:
type: string
unauthorized:
type: array
items:
type: string
description: |
A list of names of streams that the requesting user/bot was not
authorized to subscribe to. Only present if `authorization_errors_fatal=false`.
InvalidApiKeyError:
allOf:
- $ref: "#/components/schemas/JsonError"
- example: {"msg": "Invalid API key", "result": "error"}
MissingArgumentError:
allOf:
- $ref: "#/components/schemas/CodedError"
- properties:
var_name:
type: string
description: |
It contains the information about the missing parameter.
- example:
{
"code": "REQUEST_VARIABLE_MISSING",
"msg": "Missing 'content' argument",
"result": "error",
"var_name": "content",
}
UserNotAuthorizedError:
allOf:
- $ref: "#/components/schemas/CodedError"
- example:
{
"code": "BAD_REQUEST",
"msg": "User not authorized for this query",
"result": "error",
}
###################
# Shared responses
###################
responses:
SimpleSuccess:
description: Success.
content:
application/json:
schema:
$ref: "#/components/schemas/JsonSuccess"
####################
# Shared parameters
####################
parameters:
Event_types:
name: event_types
in: query
description: |
A JSON-encoded array indicating which types of events you're interested
in. Values that you might find useful include:
* **message** (messages)
* **subscription** (changes in your subscriptions)
* **realm_user** (changes to users in the organization and
their properties, such as their name).
If you do not specify this parameter, you will receive all
events, and have to filter out the events not relevant to
your client in your client code. For most applications, one
is only interested in messages, so one specifies:
`event_types=['message']`
content:
application/json:
schema:
type: array
items:
type: string
example: ["message"]
required: false
Narrow:
name: narrow
in: query
description: |
A JSON-encoded array of arrays of length 2 indicating the
narrow for which you'd like to receive events for. For
instance, to receive events for the stream `Denmark`, you
would specify `narrow=[['stream', 'Denmark']]`. Another
example is `narrow=[['is', 'private']]` for private messages.
Default is `[]`.
content:
application/json:
schema:
type: array
items:
type: array
items:
type: string
default: []
example: [["stream", "Denmark"]]
required: false
GroupId:
name: group_id
in: path
description: |
The ID of the target user group.
schema:
type: integer
example: 42
required: true
Topic:
name: topic
in: query
description: |
The topic of the message. Only required for stream messages
(`type="stream"`), ignored otherwise.
Maximum length of 60 characters.
**Changes**: New in Zulip 2.0. Previous Zulip releases encoded
this as `subject`, which is currently a deprecated alias.
schema:
type: string
example: Castle
QueueId:
name: queue_id
in: query
description: |
The ID of an event queue that was previously registered via `POST
/api/v1/register` (see [Register a queue](/api/register-queue)).
schema:
type: string
example: 1375801870:2942
required: true
Stream:
name: stream
in: query
description: |
The name of the stream to access.
schema:
type: string
example: Denmark
StreamIdInQuery:
name: stream_id
in: query
description: |
The ID of the stream to access.
schema:
type: integer
example: 42
StreamIdInPath:
name: stream_id
in: path
description: |
The ID of the stream to access.
schema:
type: integer
example: 42
required: true
ClientGravatar:
name: client_gravatar
in: query
description: |
Whether the client supports computing gravatars URLs. If
enabled, `avatar_url` will be included in the response only
if there is a Zulip avatar, and will be `null` for users who
are using gravatar as their avatar. This option
significantly reduces the compressed size of user data,
since gravatar URLs are long, random strings and thus do not
compress well. The `client_gravatar` field is set to `true` if
clients can compute their own gravatars.
schema:
type: boolean
default: false
example: true
RequiredContent:
name: content
in: query
description: |
The content of the message. Maximum message size of 10000 bytes.
schema:
type: string
example: Hello
required: true
OptionalContent:
name: content
in: query
description: |
The content of the message. Maximum message size of 10000 bytes.
schema:
type: string
example: Hello
MessageId:
name: message_id
in: path
description: |
The target message's ID.
schema:
type: integer
example: 42
required: true
UserId:
name: user_id
in: path
description: |
The target user's ID.
schema:
type: integer
example: 12
required: true
StreamPostPolicy:
name: stream_post_policy
in: query
description: |
Policy for which users can post messages to the stream.
* 1 => Any user can post.
* 2 => Only administrators can post.
* 3 => Only new members can post.
**Changes**: New in Zulip 3.0, replacing the previous
`is_announcement_only` boolean.
schema:
type: integer
default: 1
example: 2
required: false
HistoryPublicToSubscribers:
name: history_public_to_subscribers
in: query
description: |
Whether the stream's message history should be available to
newly subscribed members, or users can only access messages
they actually received while subscribed to the stream.
Corresponds to the [shared history](/help/stream-permissions)
option in documentation.
schema:
type: boolean
example: false
required: false
IncludeSubscribers:
name: include_subscribers
in: query
description: |
Whether each returned stream object should include a `subscribers`
field containing a list of the user IDs of its subscribers.
(This may be significantly slower in organizations with
thousands of users subscribed to many streams.)
**Changes**: New in Zulip 2.1.0.
schema:
type: boolean
default: false
example: true
EmojiName:
name: emoji_name
in: query
description: |
The target emoji's human-readable name.
To find an emoji's name, hover over a message to reveal
three icons on the right, then click the smiley face icon.
Images of available reaction emojis appear. Hover over the
emoji you want, and note that emoji's text name.
schema:
type: string
example: "octopus"
IncludeCustomProfileFields:
name: include_custom_profile_fields
in: query
description: |
Whether the client wants [custom profile field](/help/add-custom-profile-fields)
data to be included in the response.
**Changes**: New in Zulip 2.1.0. Previous versions do no offer these
data via the API.
schema:
type: boolean
default: false
example: true
Principals:
name: principals
in: query
description: |
A list of user ids (preferred) or Zulip display email
addresses of the users to be subscribed to or unsubscribed
from the streams specified in the `subscriptions` parameter. If
not provided, then the requesting user/bot is subscribed.
**Changes**: The integer format is new in Zulip 3.0 (Feature level 9).
content:
application/json:
schema:
type: array
items:
oneOf:
- type: string
- type: integer
example: ["ZOE@zulip.com"]
ReactionType:
name: reaction_type
in: query
description: |
If an app is adding/removing a vote on an existing reaction,
it should pass this parameter using the value the server provided
for the existing reaction for specificity. Supported values:
* `unicode_emoji`: Unicode emoji (`emoji_code` will be its unicode codepoint).
* `realm_emoji`: Custom emoji. (`emoji_code` will be its ID).
* `zulip_extra_emoji`: Special emoji included with Zulip. Exists to
namespace the `zulip` emoji.
**Changes**: In Zulip 3.0 (feature level 2), this become
optional for [custom emoji](/help/add-custom-emoji);
previously, this endpoint assumed `unicode_emoji` if this
parameter was not specified.
schema:
type: string
example: "unicode_emoji"
required: false
EmojiCode:
name: emoji_code
in: query
description: |
A unique identifier, defining the specific emoji codepoint requested,
within the namespace of the `reaction_type`.
For most API clients, you won't need this, but it's important
for Zulip apps to handle rare corner cases when
adding/removing votes on an emoji reaction added previously by
another user.
If the existing reaction was added when the Zulip server was
using a previous version of the emoji data mapping between
Unicode codepoints and human-readable names, sending the
`emoji_code` in the data for the original reaction allows the
Zulip server to correctly interpret your upvote as an upvote
rather than a reaction with a "diffenent" emoji.
schema:
type: string
example: "1f419"
required: false
MessageRetentionDays:
name: message_retention_days
in: query
description: |
Number of days that messages sent to this stream will be stored
before being automatically deleted by the [message retention
policy](/help/message-retention-policy). Two special string format
values are supported:
* "realm_default" => Return to the organization-level setting.
* "forever" => Retain messages forever.
**Changes**: New in Zulip 3.0 (feature level 17).
schema:
oneOf:
- type: string
- type: integer
example: "20"
required: false