snapshot of https://github.com/zulip/zulip.git @ 48c69911c7dd4e03b20552eb3bd77ad8151c1357 (2026-09-15)
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled

This commit is contained in:
upstream-mirror
2026-09-15 15:05:30 +05:00
commit 64898b2c79
8999 changed files with 1757358 additions and 0 deletions

View File

@@ -0,0 +1,31 @@
{generate_api_header(API_ENDPOINT_NAME)}
## Usage examples
{start_tabs}
{generate_code_example(python)|API_ENDPOINT_NAME|example}
{generate_code_example(javascript)|API_ENDPOINT_NAME|example}
{tab|curl}
{generate_code_example(curl)|API_ENDPOINT_NAME|example}
{end_tabs}
## Parameters
{generate_api_arguments_table|zulip.yaml|API_ENDPOINT_NAME}
{generate_parameter_description(API_ENDPOINT_NAME)}
## Response
{generate_return_values_table|zulip.yaml|API_ENDPOINT_NAME}
{generate_response_description(API_ENDPOINT_NAME)}
#### Example response(s)
{generate_code_example|API_ENDPOINT_NAME|fixture}

153
api_docs/api-keys.md Normal file
View File

@@ -0,0 +1,153 @@
# API keys and `zuliprc` files
An **API key** is how a user or bot can identify their account to Zulip.
A **`zuliprc` file** is a configuration file written in the [INI file
format](https://en.wikipedia.org/wiki/INI_file), which contains key-value
pairs, such as an API key and other configuration values, that are
necessary for using the Zulip API with a specific user or bot account on
a Zulip server, for example:
```
[api]
key=<bot API key>
email=<bot email address>
site=<Zulip server's URL>
...
```
For the official
clients, such as the [Python bindings](/api/configuring-python-bindings),
we recommend [downloading a `zuliprc` file](#download-a-zuliprc-file).
## Get an API key
{start_tabs}
{tab|for-a-bot}
{settings_tab|your-bots}
1. In the **Actions** column, click the **manage bot**
(<i class="zulip-icon zulip-icon-user-cog"></i>) icon,
and scroll down to **API key**.
1. Click the **copy**
(<i class="zulip-icon zulip-icon-copy"></i>) icon to
copy the bot's API key to your clipboard.
!!! warn ""
Anyone with a bot's API key can impersonate the bot, so be careful with it!
{tab|for-yourself}
{settings_tab|account-and-privacy}
1. Under **API key**, click **Manage your API key**.
1. Enter your password, and click **Get API key**. If you don't know your
password, click **reset it** and follow the instructions from there.
1. Copy your API key.
!!! warn ""
Anyone with your API key can impersonate you, so be doubly careful with it.
{end_tabs}
## Invalidate an API key
To invalidate an existing API key, you have to generate a new key. Generating a
new API key will immediately log you out of this account on all mobile devices.
{start_tabs}
{tab|for-a-bot}
{settings_tab|your-bots}
1. In the **Actions** column, click the **manage bot**
(<i class="zulip-icon zulip-icon-user-cog"></i>) icon,
and scroll down to **API key**.
1. Click the **generate new API key**
(<i class="zulip-icon zulip-icon-refresh-cw"></i>) icon.
{tab|for-yourself}
{settings_tab|account-and-privacy}
1. Under **API key**, click **Manage your API key**.
1. Enter your password, and click **Get API key**. If you don't know your
password, click **reset it** and follow the instructions from there.
1. Click **Generate new API key**
{end_tabs}
### Download a `zuliprc` file
{start_tabs}
{tab|for-a-bot}
{settings_tab|your-bots}
1. In the **Actions** column, click the **manage bot**
(<i class="zulip-icon zulip-icon-user-cog"></i>) icon,
and scroll down to **Zuliprc configuration**.
1. Click the **download**
(<i class="zulip-icon zulip-icon-download"></i>) icon
to download the bot's `zuliprc` file, or the **copy**
(<i class="zulip-icon zulip-icon-copy"></i>) icon to
copy the file's content to your clipboard.
!!! warn ""
Anyone with a bot's API key can impersonate the bot, so be careful with it!
{tab|for-yourself}
{settings_tab|account-and-privacy}
1. Under **API key**, click **Manage your API key**.
1. Enter your password, and click **Get API key**. If you don't know your
password, click **reset it** and follow the
instructions from there.
1. Click **Download zuliprc** to download your `zuliprc` file.
1. (optional) If you'd like your credentials to be used by default
when using the Zulip API on your computer, move the `zuliprc` file
to `~/.zuliprc` in your home directory.
!!! warn ""
Anyone with your API key can impersonate you, so be doubly careful with it.
{end_tabs}
### Configuration keys and environment variables
The keys you can use in a `zuliprc` file (and their equivalent
[environment variables](https://en.wikipedia.org/wiki/Environment_variable))
can be found in the following table:
| `zuliprc` key | Environment variable | Required | Description |
| --- | --- | --- | --- |
| `key` | `ZULIP_API_KEY` | Yes | The user's [API key](#get-an-api-key). |
| `email` | `ZULIP_EMAIL` | Yes | The email address of the user who owns the API key mentioned above. |
| `site` | `ZULIP_SITE` | No | URL where the Zulip server is located. |
| `client_cert_key` | `ZULIP_CERT_KEY` | No | Path to the SSL/TLS private key that the binding should use to connect to the server. |
| `client_cert`| `ZULIP_CERT` | No* | The public counterpart of `client_cert_key`/`ZULIP_CERT_KEY`. _*This setting is required if a cert key has been set._ |
| `client_bundle` | `ZULIP_CERT_BUNDLE` | No | Path where the server's PEM-encoded certificate is located. CA certificates are also accepted, in case those CA's have issued the server's certificate. Defaults to the built-in CA bundle trusted by Python. |
| `insecure` | `ZULIP_ALLOW_INSECURE` | No | Allows connecting to Zulip servers with an invalid SSL/TLS certificate. Please note that enabling this will make the HTTPS connection insecure. Defaults to `false`. |
## Related articles
* [Configuring the Python bindings](/api/configuring-python-bindings)

4709
api_docs/changelog.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,60 @@
# Client libraries
These API client libraries make it easy to work with Zulip's REST API
in your favorite language.
## Official libraries
These libraries are maintained by members of the Zulip core team. The
Python library is the most complete and best documented.
* [Python](https://github.com/zulip/python-zulip-api)
* [JavaScript](https://github.com/zulip/zulip-js)
## User maintained libraries
The Zulip core team doesn't have the resources to maintain
high-quality libraries for every programming language. We've
collected a list of user-maintained libraries for popular languages:
* [Clojure](https://github.com/thieman/clojure-zulip)
* [C#](https://github.com/zulip/zulip-csharp)
* [Go](https://github.com/ifo/gozulipbot)
* [Java](https://github.com/taliox/zulip-java-rest)
* [Kotlin](https://gitlab.com/ppiag/kzulip)
* [PHP](https://github.com/mrferos/zulip-php-client)
* [Ruby](https://github.com/raws/wonder-llama)
* [Swift](https://github.com/zulip/swift-zulip-api)
### Contributing
Contributing to improve language libraries is appreciated, as is
writing new ones. If you actively maintain a Zulip language binding
and would like it to be listed here (or would like to collaborate with
us in making it an official library), post in [this
topic][integrations-thread] in
[the Zulip development community](https://zulip.com/development-community/)
or submit a pull request [updating this
page](https://zulip.readthedocs.io/en/latest/documentation/api.html).
[integrations-thread]: https://chat.zulip.org/#narrow/channel/127-integrations/topic/API.20client.20libraries/
### Outdated
!!! tip ""
The following projects are not actively maintained. Since
Zulip's core APIs have been stable for 5 years, even very
old libraries can be useful.
* [Lua](https://github.com/deckycoss/zulua)
* [Erlang](https://github.com/femnad/tuplre)
* [PHP](https://github.com/federicoq/zulip-php)
* [Go](https://github.com/decached/go-zulip)
* [Haskell](https://github.com/yamadapc/hzulip)
* [Chicken Scheme](https://github.com/yamadapc/zulip-scheme)
* [Scala](https://github.com/cqfd/zulip-scala)
* [EventMachine](https://github.com/cqfd/zulip_machine)
* [Ruby](https://github.com/verg/zulip-rb)
* [Perl](https://github.com/Stantheman/WebService-Zulip)
* [.Net](https://github.com/Shayan-To/ZulipClientApi)

View File

@@ -0,0 +1,30 @@
# Configuring the Python bindings
Zulip provides a set of tools that allows interacting with its API more
easily, called the [Python bindings](https://pypi.python.org/pypi/zulip/).
One of the most notable use cases for these bindings are bots developed
using Zulip's [bot framework](/help/writing-bots).
In order to use them, you need to configure them with your identity
(account, API key, and Zulip server URL). There are a few ways to
achieve that:
- Using a [`zuliprc` file](/api/api-keys#download-a-zuliprc-file), referenced via
the `--config-file` option or the `config_file` option to the
`zulip.Client` constructor (recommended for bots).
- Using a [`zuliprc` file](/api/api-keys#download-a-zuliprc-file) in your home
directory at `~/.zuliprc` (recommended for your own API key).
- Using the [environment
variables](https://en.wikipedia.org/wiki/Environment_variable)
documented [here](/api/api-keys#configuration-keys-and-environment-variables).
- Using the `--api-key`, `--email`, and `--site` variables as command
line parameters.
- Using the `api_key`, `email`, and `site` parameters to the
`zulip.Client` constructor.
## Related articles
* [Installation instructions](/api/installation-instructions)
* [API keys](/api/api-keys)
* [Running bots](/help/running-bots)
* [Deploying bots](/help/deploying-bots)

View File

@@ -0,0 +1,210 @@
# Construct a narrow
A **narrow** is a set of filters for Zulip messages, that can be based
on many different factors (like sender, channel, topic, search
keywords, etc.). Narrows are used in various places in the Zulip
API (most importantly, in the API for fetching messages).
It is simplest to explain the algorithm for encoding a search as a
narrow using a single example. Consider the following search query
(written as it would be entered in the Zulip web app's search box).
It filters for messages sent to channel `announce`, not sent by
`iago@zulip.com`, and containing the words `cool` and `sunglasses`:
```
channel:announce -sender:iago@zulip.com cool sunglasses
```
This query would be JSON-encoded for use in the Zulip API using JSON
as a list of simple objects, as follows:
```json
[
{
"operator": "channel",
"operand": "announce"
},
{
"operator": "sender",
"operand": "iago@zulip.com",
"negated": true
},
{
"operator": "search",
"operand": "cool sunglasses"
}
]
```
The Zulip help center article on [searching for messages](/help/search-for-messages)
documents the majority of the search/narrow options supported by the
Zulip API.
Note that many narrows, including all that lack a `channel` or `channels`
operator, search the current user's personal message history. See
[searching shared history](/help/search-for-messages#search-shared-history)
for details.
Clients should note that the `is:unread` filter takes advantage of the
fact that there is a database index for unread messages, which can be an
important optimization when fetching messages in certain cases (e.g.,
when [adding the `read` flag to a user's personal
messages](/api/update-message-flags-for-narrow)).
Note: When the value of `realm_empty_topic_display_name` found in
the [POST /register](/api/register-queue) response is used as an operand
for the `"topic"` operator in the narrow, it is interpreted
as an empty string.
## Changes
* In Zulip 12.0 (feature level 489), support was added for a new
filter, `channels:archived`, which returns messages the current user
received in channels that have been [archived](/help/archive-a-channel).
* In Zulip 12.0 (feature level 446), add the `mentions` operator,
matching messages that contain a direct personal mention of the
specified user.
* In Zulip 10.0 (feature level 366), support was added for a new
`is:muted` operator combination, matching messages in topics and
channels that the user has [muted](/help/mute-a-topic).
* Before Zulip 10.0 (feature level 334), empty string was not a valid
topic name for channel messages.
* In Zulip 9.0 (feature level 271), support was added for a new filter
operator, `with`, which uses a [message ID](#message-ids) for its
operand, and is designed for creating permanent links to topics.
* In Zulip 9.0 (feature level 265), support was added for a new
`is:followed` filter, matching messages in topics that the current
user is [following](/help/follow-a-topic).
* In Zulip 9.0 (feature level 250), support was added for two filters
related to stream messages: `channel` and `channels`. The `channel`
operator is an alias for the `stream` operator. The `channels`
operator is an alias for the `streams` operator. Both `channel` and
`channels` return the same exact results as `stream` and `streams`
respectively.
* In Zulip 9.0 (feature level 249), support was added for a new filter,
`has:reaction`, which returns messages that have at least one [emoji
reaction](/help/emoji-reactions).
* In Zulip 7.0 (feature level 177), support was added for three filters
related to direct messages: `is:dm`, `dm` and `dm-including`. The
`dm` operator replaced and deprecated the `pm-with` operator. The
`is:dm` filter replaced and deprecated the `is:private` filter. The
`dm-including` operator replaced and deprecated the `group-pm-with`
operator.
* The `dm-including` and `group-pm-with` operators return slightly
different results. For example, `dm-including:1234` returns all
direct messages (1-on-1 and group) that include the current user
and the user with the unique user ID of `1234`. On the other hand,
`group-pm-with:1234` returned only group direct messages that
included the current user and the user with the unique user ID of
`1234`.
* Both `dm` and `is:dm` are aliases of `pm-with` and `is:private`
respectively, and return the same exact results that the
deprecated filters did.
## Narrows that use IDs
### Message IDs
The `id` and `with` operators use message IDs for their operands. The
message ID operand for these two operators may be encoded as either a
number or a string.
* `id:12345`: Search for only the message with ID `12345`.
* `with:12345`: Search for the conversation that contains the message
with ID `12345`.
The `id` operator returns the message with the specified ID if it exists,
and if it can be accessed by the user.
The `with` operator is designed to be used for permanent links to
topics, which means they should continue to work when the topic is
[moved](/help/move-content-to-another-topic) or
[resolved](/help/resolve-a-topic). If the message with the specified
ID exists, and can be accessed by the user, then it will return
messages with the `channel`/`topic`/`dm` operators corresponding to
the current conversation containing that message, replacing any such
operators included in the original narrow query.
If no such message exists, or the message ID represents a message that
is inaccessible to the user, this operator will be ignored (rather
than throwing an error) if the remaining operators uniquely identify a
conversation (i.e., they contain `channel` and `topic` terms or `dm`
term). This behavior is intended to provide the best possible
experience for links to private channels with protected history.
The [help center](/help/search-for-messages#search-by-message-id) also
documents the `near` operator for searching for messages by ID, but
this narrow operator has no effect on filtering messages when sent to
the server. In practice, when the `near` operator is used to search for
messages, or is part of a URL fragment, the value of its operand should
instead be used for the value of the `anchor` parameter in endpoints
that also accept a `narrow` parameter; see
[GET /messages][anchor-get-messages] and
[POST /messages/flags/narrow][anchor-post-flags].
**Changes**: Prior to Zulip 8.0 (feature level 194), the message ID
operand for the `id` operator needed to be encoded as a string.
```json
[
{
"operator": "id",
"operand": 12345
}
]
```
### Channel and user IDs
There are a few additional narrow/search options (new in Zulip 2.1)
that use either channel IDs or user IDs that are not documented in the
help center because they are primarily useful to API clients:
* `channel:1234`: Search messages sent to the channel with ID `1234`.
* `sender:1234`: Search messages sent by user ID `1234`.
* `dm:1234`: Search the direct message conversation between
you and user ID `1234`.
* `dm:1234,5678`: Search the direct message conversation between
you, user ID `1234`, and user ID `5678`.
* `dm-including:1234`: Search all direct messages (1-on-1 and group)
that include you and user ID `1234`.
!!! tip ""
A user ID can be found by [viewing a user's profile][view-profile]
in the web or desktop apps. A channel ID can be found when [browsing
channels][browse-channels] in the web or desktop apps.
The operands for these search options must be encoded either as an
integer ID or a JSON list of integer IDs. For example, to query
messages sent by a user 1234 to a direct message thread with yourself,
user 1234, and user 5678, the correct JSON-encoded query is:
```json
[
{
"operator": "dm",
"operand": [1234, 5678]
},
{
"operator": "sender",
"operand": 1234
}
]
```
[view-profile]: /help/view-someones-profile
[browse-channels]: /help/introduction-to-channels#browse-and-subscribe-to-channels
[anchor-get-messages]: /api/get-messages#parameter-anchor
[anchor-post-flags]: /api/update-message-flags-for-narrow#parameter-anchor

View File

@@ -0,0 +1,51 @@
{generate_api_header(/scheduled_messages:post)}
## Usage examples
{start_tabs}
{generate_code_example(python)|/scheduled_messages:post|example}
{generate_code_example(javascript)|/scheduled_messages:post|example}
{tab|curl}
{!curl-auth-credentials.md!}
``` curl
# Create a scheduled channel message
curl -X POST {{ api_url }}/v1/scheduled_messages \
-u EMAIL_ADDRESS:API_KEY \
--data-urlencode type=stream \
--data-urlencode to=9 \
--data-urlencode topic=Hello \
--data-urlencode 'content=Nice to meet everyone!' \
--data-urlencode scheduled_delivery_timestamp=3165826990
# Create a scheduled direct message
curl -X POST {{ api_url }}/v1/messages \
-u EMAIL_ADDRESS:API_KEY \
--data-urlencode type=direct \
--data-urlencode 'to=[9, 10]' \
--data-urlencode 'content=Can we meet on Monday?' \
--data-urlencode scheduled_delivery_timestamp=3165826990
```
{end_tabs}
## Parameters
{generate_api_arguments_table|zulip.yaml|/scheduled_messages:post}
{generate_parameter_description(/scheduled_messages:post)}
## Response
{generate_return_values_table|zulip.yaml|/scheduled_messages:post}
{generate_response_description(/scheduled_messages:post)}
#### Example response(s)
{generate_code_example|/scheduled_messages:post|fixture}

View File

@@ -0,0 +1,6 @@
# Create a channel
You can create a channel using Zulip's REST API by submitting a
[subscribe](/api/subscribe) request with a channel name that
doesn't yet exist and passing appropriate parameters to define
the initial configuration of the new channel.

View File

@@ -0,0 +1,122 @@
# Group-setting values
Settings defining permissions in Zulip are increasingly represented
using [user groups](/help/user-groups), which offer much more flexible
configuration than the older [roles](/api/roles-and-permissions) system.
!!! warn ""
**Note**: Many group-valued settings are configured to require
a single system group for their value via
`server_supported_permission_settings`, pending web app UI
changes to fully support group-setting values.
**Changes**: Before Zulip 10.0 (feature level 309), only system
groups were permitted values for group-setting values in
production environments, regardless of the values in
`server_supported_permission_settings`.
In the API, these settings are represented using a **group-setting
value**, which can take two forms:
- An integer user group ID, which can be either a named user group
visible in the UI or a [role-based system group](#system-groups).
- An object with fields `direct_members`, containing a list of
integer user IDs, and `direct_subgroups`, containing a list of
integer group IDs. The setting's value is the union of the
identified collection of users and groups.
Group-setting values in the object form can be thought of as an
anonymous group. They function very much like a named user group
object, and remove the naming and UI overhead involved in creating
a visible user group just to store the value of a single setting.
The server will canonicalize an object with an empty `direct_members`
list and a `direct_subgroups` list that contains just a single group
ID to the integer format.
## System groups
The Zulip server maintains a collection of system groups that
correspond to the users with a given role; this makes it convenient to
store concepts like "all administrators" in a group-setting
value. These use a special naming convention and can be recognized by
the `is_system_group` property on their group object.
The following system groups are maintained by the Zulip server:
- `role:internet`: Everyone on the Internet has this permission; this
is used to configure the [public access
option](/help/public-access-option).
- `role:everyone`: All users, including guests.
- `role:members`: All users, excluding guests.
- `role:fullmembers`: All [full
members](https://zulip.com/api/roles-and-permissions#determining-if-a-user-is-a-full-member)
of the organization.
- `role:moderators`: All users with at least the moderator role.
- `role:administrators`: All users with at least the administrator
role.
- `role:owners`: All users with the owner role.
- `role:nobody`: The formal empty group. Used in the API to represent
disabling a feature.
Client UI for setting a permission or displaying a group (when
silently mentioned, for example) is encouraged to display system
groups using their description, rather than using their `role:}`
names, which are chosen to be unique and clear in the API.
System groups should generally not be displayed in UI for
administering an organization's user groups, since they are not
directly mutable.
## Updating group-setting values
The Zulip API uses a special format for modifying an existing setting
using a group-setting value.
A **group-setting update** is an object with a `new` field and an
optional `old` field, each containing a group-setting value. The
setting's value will be set to the membership expressed by the `new`
field.
The `old` field expresses the client's understanding of the current
value of the setting. If the `old` field is present and does not match
the actual current value of the setting, then the request will fail
with error code `EXPECTATION_MISMATCH` and no changes will be applied.
When a user edits the setting in a UI, the resulting API request
should generally always include the `old` field, giving the value
the list had when the user started editing. This accurately expresses
the user's intent, and if two users edit the same list around the
same time, it prevents a situation where the second change
accidentally reverts the first one without either user noticing.
Omitting `old` is appropriate where the intent really is a new complete
list rather than an edit, for example in an integration that syncs the
list from an external source of truth.
## Permitted values
Not every possible group-setting value is a valid configuration for a
given group-based setting. For example, as a security hardening
measure, some administrative permissions should never be exercised by
guest users, and the system group for all users, including guests,
should not be offered to users as an option for those settings.
Others have restrictions to only permit system groups due to UI
components not yet having been migrated to support a broader set of
values. In order to avoid this configuration ending up hardcoded in
clients, every permission setting using this framework has an entry in
the `server_supported_permission_settings` section of the [`POST
/register`](/api/register-queue) response.
Clients that support mutating group-settings values must parse that
part of the `register` payload in order to compute the set of
permitted values to offer to the user and avoid server-side errors
when trying to save a value.
Note specifically that the `allow_everyone_group` field, which
determines whether the setting can have the value of "all user
accounts, including guests" also controls whether guests users can
exercise the permission regardless of their membership in the
group-setting value.

103
api_docs/http-headers.md Normal file
View File

@@ -0,0 +1,103 @@
# HTTP headers
This page documents the HTTP headers used by the Zulip API.
!!! tip ""
Full details of the HTTP requests are given in the `curl` example
on each endpoint's documentation page. You can access curl's
documentation at [`man curl`](https://curl.se/docs/manpage.html).
## The `Authorization` header
Most important is that API clients authenticate to the server using
HTTP Basic authentication. If you're using the official [Python or
JavaScript bindings](/api/installation-instructions), this is taken
care of when you configure said bindings.
Otherwise, to authenticate an API request:
- Use HTTP `Basic` authentication, which is described [here][mdn-auth-headers].
This means sending an HTTP header named `Authorization`, with your
credentials [in a certain format][mdn-basic-auth].
- For `Basic` authentication credentials in the Zulip API, a "username"
takes the form of an email address, and a "password" takes the form of
an API key. In the `curl` example for each endpoint, this is shown as:
`-u EMAIL_ADDRESS:API_KEY`.
- A bot's credentials can be obtained through the web and desktop apps'
[bot management UI](/help/manage-a-bot) or by [downloading the bot's
`zuliprc` file](/api/api-keys#download-a-zuliprc-file).
- See [fetch an API key (production)](/api/fetch-api-key) for the
password-based authentication flow for getting a user's credentials.
## The `User-Agent` header
Clients are not required to pass a `User-Agent` HTTP header, but we
highly recommend doing so when writing an integration. It's easy to do
and it can help save time when debugging issues related to an API
client.
If provided, the Zulip server will parse the `User-Agent` HTTP header
in order to identify specific clients and integrations. This
information is used by the server for logging, [usage
statistics](/help/analytics), and on rare occasions, for
backwards-compatibility logic to preserve support for older versions
of official clients.
Official Zulip clients and integrations use a `User-Agent` that starts
with something like `ZulipMobile/20.0.103 `, encoding the name of the
application and it's version.
Zulip's official API bindings have reasonable defaults for
`User-Agent`. For example, the official Zulip Python bindings have a
default `User-Agent` starting with `ZulipPython/{version}`, where
`version` is the version of the library.
You can give your bot/integration its own name by passing the `client`
parameter when initializing the Python bindings. For example, the
official Zulip Nagios integration is initialized like this:
``` python
client = zulip.Client(
config_file=opts.config, client=f"ZulipNagios/{VERSION}"
)
```
If you are working on an integration that you plan to share outside
your organization, you can get help picking a good name in
[#integrations][integrations-channel] in the [Zulip development
community](https://zulip.com/development-community/).
## Rate-limiting response headers
To help clients avoid exceeding rate limits, Zulip sets the following
HTTP headers in all API responses:
* `X-RateLimit-Remaining`: The number of additional requests of this
type that the client can send before exceeding its limit.
* `X-RateLimit-Limit`: The limit that would be applicable to a client
that had not made any recent requests of this type. This is useful
for designing a client's burst behavior so as to avoid ever reaching
a rate limit.
* `X-RateLimit-Reset`: The time at which the client will no longer
have any rate limits applied to it (and thus could do a burst of
`X-RateLimit-Limit` requests).
[Zulip's rate limiting rules are configurable][rate-limiting-rules],
and can vary by server and over time. The default configuration
currently limits:
* Every user is limited to 200 total API requests per minute.
* Separate, much lower limits for authentication/login attempts.
When the Zulip server has configured multiple rate limits that apply
to a given request, the values returned will be for the strictest
limit.
[rate-limiting-rules]: https://zulip.readthedocs.io/en/latest/production/securing-your-zulip-server.html#rate-limiting
[integrations-channel]: https://chat.zulip.org/#narrow/channel/127-integrations/
[mdn-auth-headers]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Authorization
[mdn-basic-auth]: https://developer.mozilla.org/en-US/docs/Web/HTTP/Reference/Headers/Authorization#basic_authentication_2

View File

@@ -0,0 +1,3 @@
!!! warn ""
This endpoint is only available to organization administrators.

View File

@@ -0,0 +1,2 @@
!!! warn ""
This endpoint is only available to organization owners.

View File

@@ -0,0 +1,6 @@
!!! warn ""
**Note**: The Zulip web application implementation of this feature is
pending. For information about the current state of this API and the
feature's development, reach out in [our development
community](https://chat.zulip.org).

View File

@@ -0,0 +1,6 @@
The [`-u` line][curl-man-user] implements HTTP `Basic` authentication.
See the [`Authorization` header][auth-header] documentation for how
to get those credentials for Zulip users and bots.
[curl-man-user]: https://curl.se/docs/manpage.html#--user
[auth-header]: /api/http-headers#the-authorization-header

View File

View File

@@ -0,0 +1,208 @@
## Messages
* [Send a message](/api/send-message)
* [Upload a file](/api/upload-file)
* [Edit a message](/api/update-message)
* [Delete a message](/api/delete-message)
* [Get messages](/api/get-messages)
* [Construct a narrow](/api/construct-narrow)
* [Add an emoji reaction](/api/add-reaction)
* [Remove an emoji reaction](/api/remove-reaction)
* [Render a message](/api/render-message)
* [Fetch a single message](/api/get-message)
* [Check if messages match a narrow](/api/check-messages-match-narrow)
* [Get a message's edit history](/api/get-message-history)
* [Update personal message flags](/api/update-message-flags)
* [Update personal message flags for narrow](/api/update-message-flags-for-narrow)
* [Mark all messages as read](/api/mark-all-as-read)
* [Mark messages in a channel as read](/api/mark-stream-as-read)
* [Mark messages in a topic as read](/api/mark-topic-as-read)
* [Get a message's read receipts](/api/get-read-receipts)
* [Get temporary URL for an uploaded file](/api/get-file-temporary-url)
* [Check thumbnail status](/api/check-thumbnail-status)
* [Report a message](/api/report-message)
## Scheduled messages
* [Get scheduled messages](/api/get-scheduled-messages)
* [Create a scheduled message](/api/create-scheduled-message)
* [Edit a scheduled message](/api/update-scheduled-message)
* [Delete a scheduled message](/api/delete-scheduled-message)
## Message reminders
* [Create a message reminder](/api/create-message-reminder)
* [Get reminders](/api/get-reminders)
* [Delete a reminder](/api/delete-reminder)
## Drafts
* [Get drafts](/api/get-drafts)
* [Create drafts](/api/create-drafts)
* [Edit a draft](/api/edit-draft)
* [Delete a draft](/api/delete-draft)
* [Get all saved snippets](/api/get-saved-snippets)
* [Create a saved snippet](/api/create-saved-snippet)
* [Edit a saved snippet](/api/edit-saved-snippet)
* [Delete a saved snippet](/api/delete-saved-snippet)
## Navigation views
* [Get all navigation views](/api/get-navigation-views)
* [Add a navigation view](/api/add-navigation-view)
* [Update the navigation view](/api/edit-navigation-view)
* [Remove a navigation view](/api/remove-navigation-view)
## Channels
* [Get subscribed channels](/api/get-subscriptions)
* [Subscribe to a channel](/api/subscribe)
* [Unsubscribe from a channel](/api/unsubscribe)
* [Get subscription status](/api/get-subscription-status)
* [Get channel subscribers](/api/get-subscribers)
* [Get a user's subscribed channels](/api/get-user-channels)
* [Update a subscription setting](/api/update-subscription-property)
* [Bulk update subscription settings](/api/update-subscription-settings)
* [Get all channels](/api/get-streams)
* [Get a channel by ID](/api/get-stream-by-id)
* [Get channel ID](/api/get-stream-id)
* [Create a channel](/api/create-channel)
* [Update a channel](/api/update-stream)
* [Archive a channel](/api/archive-stream)
* [Get channel's email address](/api/get-stream-email-address)
* [Get topics in a channel](/api/get-stream-topics)
* [Topic muting](/api/mute-topic)
* [Update personal preferences for a topic](/api/update-user-topic)
* [Delete a topic](/api/delete-topic)
* [Add a default channel](/api/add-default-stream)
* [Remove a default channel](/api/remove-default-stream)
* [Create a channel folder](/api/create-channel-folder)
* [Get channel folders](/api/get-channel-folders)
* [Reorder channel folders](/api/patch-channel-folders)
* [Update a channel folder](/api/update-channel-folder)
## Users
* [Get a user](/api/get-user)
* [Get a user by email](/api/get-user-by-email)
* [Get own user](/api/get-own-user)
* [Get users](/api/get-users)
* [Create a user](/api/create-user)
* [Update a user](/api/update-user)
* [Update a user by email](/api/update-user-by-email)
* [Deactivate a user](/api/deactivate-user)
* [Deactivate own user](/api/deactivate-own-user)
* [Reactivate a user](/api/reactivate-user)
* [Get a user's status](/api/get-user-status)
* [Update your status](/api/update-status)
* [Update user status](/api/update-status-for-user)
* [Update your profile data](/api/update-profile-data)
* [Remove your profile data](/api/remove-profile-data)
* [Upload your profile picture](/api/upload-avatar)
* [Delete your profile picture](/api/delete-avatar)
* [Set "typing" status](/api/set-typing-status)
* [Set "typing" status for message editing](/api/set-typing-status-for-message-edit)
* [Get a user's presence](/api/get-user-presence)
* [Get presence of all users](/api/get-presence)
* [Update your presence](/api/update-presence)
* [Get attachments](/api/get-attachments)
* [Delete an attachment](/api/remove-attachment)
* [Update settings](/api/update-settings)
* [Get user groups](/api/get-user-groups)
* [Create a user group](/api/create-user-group)
* [Update a user group](/api/update-user-group)
* [Deactivate a user group](/api/deactivate-user-group)
* [Update user group members](/api/update-user-group-members)
* [Update subgroups of a user group](/api/update-user-group-subgroups)
* [Get user group membership status](/api/get-is-user-group-member)
* [Get user group members](/api/get-user-group-members)
* [Get subgroups of a user group](/api/get-user-group-subgroups)
* [Mute a user](/api/mute-user)
* [Unmute a user](/api/unmute-user)
* [Get all alert words](/api/get-alert-words)
* [Add alert words](/api/add-alert-words)
* [Remove alert words](/api/remove-alert-words)
* [Regenerate your API key](/api/regenerate-api-key)
* [Get a bot's API key](/api/get-bot-api-key)
* [Regenerate a bot's API key](/api/regenerate-bot-api-key)
## Invitations
* [Get all invitations](/api/get-invites)
* [Send invitations](/api/send-invites)
* [Create a reusable invitation link](/api/create-invite-link)
* [Resend an email invitation](/api/resend-email-invite)
* [Revoke an email invitation](/api/revoke-email-invite)
* [Revoke a reusable invitation link](/api/revoke-invite-link)
## Server & organizations
* [Get server settings](/api/get-server-settings)
* [Get linkifiers](/api/get-linkifiers)
* [Add a linkifier](/api/add-linkifier)
* [Update a linkifier](/api/update-linkifier)
* [Remove a linkifier](/api/remove-linkifier)
* [Reorder linkifiers](/api/reorder-linkifiers)
* [Add a code playground](/api/add-code-playground)
* [Remove a code playground](/api/remove-code-playground)
* [Get all custom emoji](/api/get-custom-emoji)
* [Upload custom emoji](/api/upload-custom-emoji)
* [Deactivate custom emoji](/api/deactivate-custom-emoji)
* [Get all custom profile fields](/api/get-custom-profile-fields)
* [Reorder custom profile fields](/api/reorder-custom-profile-fields)
* [Create a custom profile field](/api/create-custom-profile-field)
* [Update a custom profile field](/api/update-custom-profile-field)
* [Delete a custom profile field](/api/delete-custom-profile-field)
* [Update realm-level defaults of user settings](/api/update-realm-user-settings-defaults)
* [Get allowed domains](/api/get-realm-domains)
* [Add an allowed domain](/api/add-realm-domain)
* [Update an allowed domain](/api/patch-realm-domain)
* [Remove an allowed domain](/api/delete-realm-domain)
* [Get all data exports](/api/get-realm-exports)
* [Create a data export](/api/export-realm)
* [Get data export consent state](/api/get-realm-export-consents)
* [Delete a data export](/api/delete-realm-export)
* [Test welcome bot custom message](/api/test-welcome-bot-custom-message)
* [Deactivate an organization](/api/deactivate-realm)
## Real-time events
* [Real time events API](/api/real-time-events)
* [Register an event queue](/api/register-queue)
* [Get events from an event queue](/api/get-events)
* [Delete an event queue](/api/delete-queue)
## Interactive bots
* [Get a bot's stored data](/api/get-bot-storage)
* [Update a bot's stored data](/api/update-bot-storage)
* [Remove a bot's stored data](/api/remove-bot-storage)
## Video call integrations
* [Create BigBlueButton video call](/api/create-big-blue-button-video-call)
* [Create Constructor Groups video call](/api/create-constructor-groups-video-call)
* [Create Nextcloud Talk video call](/api/create-nextcloud-talk-video-call)
* [Create Webex video call](/api/create-webex-video-call)
## Mobile push notifications
* [Register a logged-in device](/api/register-client-device)
* [Remove a registered device](/api/remove-client-device)
* [Send an E2EE test notification to mobile device(s)](/api/e2ee-test-notify)
* [Register E2EE push device](/api/register-push-device)
* [Register E2EE push device to bouncer](/api/register-remote-push-device)
* [Mobile notifications](/api/mobile-notifications)
* [Send a test notification to mobile device(s)](/api/test-notify)
* [Add an APNs device token](/api/add-apns-token)
* [Remove an APNs device token](/api/remove-apns-token)
* [Add an FCM registration token](/api/add-fcm-token)
* [Remove an FCM registration token](/api/remove-fcm-token)
## Specialty endpoints
* [Fetch an API key (production)](/api/fetch-api-key)
* [Fetch an API key (development only)](/api/dev-fetch-api-key)
* [Fetch an API key (JWT)](/api/jwt-fetch-api-key)
* [List users (development only)](/api/dev-list-users)
* [Outgoing webhook payloads](/api/outgoing-webhook-payload)

28
api_docs/index.md Normal file
View File

@@ -0,0 +1,28 @@
# The Zulip API
Zulip's APIs allow you to integrate other services with Zulip. This
guide should help you find the API you need:
* First, check if the tool you'd like to integrate with Zulip
[already has a native integration](/integrations/).
* Next, check if [Zapier](https://zapier.com/apps) or
[IFTTT](https://ifttt.com/search) has an integration.
[Zulip's Zapier integration](/integrations/zapier) and
[Zulip's IFTTT integration](/integrations/ifttt) often allow
integrating a new service with Zulip without writing any code.
* If you'd like to send content into Zulip, you can
[write a native incoming webhook integration][incoming-webhooks-overview]
or use [Zulip's API for sending messages](/api/send-message).
* If you're building an interactive bot that reacts to activity inside
Zulip, you'll want to look at Zulip's
[Python framework for interactive bots](/help/running-bots) or
[Zulip's real-time events API](/api/get-events).
And if you still need to build your own integration with Zulip, check out
the full [REST API](/api/rest), generally starting with
[installing the API client bindings](/api/installation-instructions).
In case you already know how you want to build your integration and you're
just looking for an API key, we've got you covered [here](/api/api-keys).
[incoming-webhooks-overview]: https://zulip.readthedocs.io/en/latest/webhooks/incoming-webhooks-overview.html

View File

@@ -0,0 +1,46 @@
# Installation instructions
Zulip's REST API is easy to work with directly, but there are API
libraries available for a few popular languages.
The Python library is the most advanced (and has tools for easily
writing interactive bots that react to messages), so we recommend it
if you're trying to decide.
{start_tabs}
{tab|python}
Install the Python API with [pip](https://pypi.python.org/pypi/zulip/):
```
pip install zulip
```
{tab|zulip-send}
Included with the Python bindings:
```
pip install zulip
```
{tab|js}
Install the JavaScript API with [npm](https://www.npmjs.com/package/zulip-js):
```
npm install zulip-js
```
{tab|curl}
No download required!
{end_tabs}
See also [user-contributed client libraries](/api/client-libraries)
for many other languages.
## Related articles
* [Configuring the Python bindings](/api/configuring-python-bindings)

View File

@@ -0,0 +1,630 @@
# Message formatting
Zulip supports an extended version of Markdown for messages, as well as
some HTML level special behavior. The Zulip help center article on [message
formatting](/help/format-your-message-using-markdown) is the primary
documentation for Zulip's markup features. This article is currently a
changelog for updates to these features.
The [render a message](/api/render-message) endpoint can be used to get
the current HTML version of any Markdown syntax for message content.
## Code blocks
**Changes**: As of Zulip 4.0 (feature level 33), [code blocks][help-code]
can have a `data-code-language` attribute attached to the outer HTML
`div` element, which records the programming language that was selected
for syntax highlighting. This field is used in the
[playgrounds][help-playgrounds] feature for code blocks.
## Global times
**Changes**: In Zulip 13.0 (feature level 503), the global time
syntax only recognizes ISO 8601 formatted timestamps.
**Changes**: In Zulip 12.0 (feature level 451), invalid timestamp formats
are now rendered as escaped literal text instead of a `<span>` element with
`timestamp-error` class and an error message.
Previously, an invalid timestamp string would be rendered as:
``` html
<span class="timestamp-error">Invalid time format: invalid</span>
```
Now, it is rendered as:
``` html
&lt;time:invalid&gt;
```
**Changes**: In Zulip 3.0 (feature level 8), added [global time
mentions][help-global-time] to supported Markdown message formatting
features.
## Links to channels, topics, and messages
Zulip's markup supports special readable Markdown syntax for [linking
to channels, topics, and
messages](/help/link-to-a-message-or-conversation). See also [Zulip
URLs](/api/zulip-urls)
Sample HTML formats are as follows:
``` html
<!-- Syntax: #**announce** -->
<a class="stream" data-stream-id="9"
href="/#narrow/channel/9-announce">
#announce
</a>
<!-- Syntax: #**announce>Zulip updates** -->
<a class="stream-topic" data-stream-id="9"
href="/#narrow/channel/9-announce/topic/Zulip.20updates/with/214">
#announce &gt; Zulip updates
</a>
<!-- Syntax: #**announce>Zulip updates**
Generated only if topic had no messages or the link was rendered
before Zulip 10.0 (feature level 347) -->
<a class="stream-topic" data-stream-id="9"
href="/#narrow/channel/9-announce/topic/Zulip.20updates">
#announce &gt; Zulip updates
</a>
<!-- Syntax: #**announce>Zulip updates@214** -->
<a class="message-link"
href="/#narrow/channel/9-announce/topic/Zulip.20updates/near/214">
#announce &gt; Zulip updates @ 💬
</a>
```
The `near` and `with` operators are documented in more detail in the
[search and URL documentation](/api/construct-narrow). When rendering
topic links with the `with` operator, the code doing the rendering may
pick the ID arbitrarily among messages accessible to the client and/or
acting user at the time of rendering. Currently, the server chooses
the message ID to use for `with` operators as the latest message ID in
the topic accessible to the user who wrote the message.
The older stream/topic link elements include a `data-stream-id`, which
historically was used in order to display the current channel name if
the channel had been renamed. That field is **deprecated**, because
displaying an updated value for the most common forms of this syntax
requires parsing the URL to get the topic to use anyway.
When a topic is an empty string, it is replaced with
`realm_empty_topic_display_name` found in the [`POST /register`](/api/register-queue)
response and wrapped with the `<em>` tag.
Sample HTML formats with `"realm_empty_topic_display_name": "general chat"`
are as follows:
```html
<!-- Syntax: #**announce>** -->
<a class="stream-topic" data-stream-id="9"
href="/#narrow/channel/9-announce/topic/with/214">
#announce &gt; <em>general chat</em>
</a>
<!-- Syntax: #**announce>**
Generated only if topic had no messages or the link was rendered
before Zulip 10.0 (feature level 347) -->
<a class="stream-topic" data-stream-id="9"
href="/#narrow/channel/9-announce/topic/">
#announce &gt; <em>general chat</em>
</a>
<!-- Syntax: #**announce>@214** -->
<a class="message-link"
href="/#narrow/channel/9-announce/topic//near/214">
#announce &gt; <em>general chat</em> @ 💬
</a>
```
**Changes**: In Zulip 11.0 (feature level 400), the server switched
its strategy for `with` URL construction to choose the latest
accessible message ID in a topic. Previously, it used the oldest.
Before Zulip 10.0 (feature level 347), the `with` field
was never used in topic link URLs generated by the server; the markup
currently used only for empty topics was used for all topic links.
Before Zulip 10.0 (feature level 346), empty string
was not a valid topic name in syntaxes for linking to topics and
messages.
In Zulip 10.0 (feature level 319), added Markdown syntax
for linking to a specific message in a conversation. Declared the
`data-stream-id` field to be deprecated as detailed above.
In Zulip 11.0 (feature level 383), clients can decide what
channel view a.stream channel link elements take you to -- i.e.,
the href for those is the default behavior of the link that also
encodes the channel alongside the data-stream-id field, but clients
can override that default based on `web_channel_default_view` setting.
## Emoji
Zulip's [emoji][help-emoji] support includes standard Unicode emoji, a
built-in Zulip custom emoji like `:zulip:` and [custom realm
emoji][help-custom-emoji]. To maximize legibility, emoji should be
displayed inline with text, at the maximum size that does not
interfere with line spacing.
**Large emoji**. Clients are recommended to display single-paragraph
messages that contain only emoji elements with a greatly increased
size. For example, Zulip the web app scales large emoji to be 2x the
size of other message emoji.
Unicode emoji, such as `:smiling_face:` (☺️ / `263a`), are represented
in the HTML by spans with the following format:
```html
<span aria-label="smiling face" class="emoji emoji-263a" role="img"
title="smiling face">:smiling_face:</span>
```
Note that Unicode emoji in messages that were originally sent on Zulip
versions older than Zulip 1.9.2 will not have the `role` or
`aria-label` attributes. Thus, clients should not rely on those fields
existing.
The `server_emoji_data_url` key in the [`POST
/register`](/api/register-queue) response contains the server's
mapping between Unicode codepoints and emoji names.
Custom emoji are represented in the HTML by image tags that also use
the `.emoji` class. The `src` URL should be resolved with respect to
the Zulip server's hostname:
```html
<-- Configured realm-specific custom emoji -->
<img alt=":example_custom_emoji:" class="emoji" title="example_custom_emoji"
src="/user_avatars/2/emoji/images/dbe43627.png">
<-- Built-in custom emoji like :zulip: -->
<img alt=":zulip:" class="emoji" title="zulip"
src="/static/generated/emoji/images/emoji/unicode/zulip.png">
```
**Changes**: Large emoji are new in Zulip 12.0 (feature level 436).
## Images
When a Zulip message is sent with a link to an uploaded image, Zulip will
also insert an image preview element with the following format:
``` html
<div class="message_inline_image">
<a href="/user_uploads/path/to/example.png" title="example.png">
<img data-original-dimensions="1920x1080"
data-original-content-type="image/png"
src="/user_uploads/thumbnail/path/to/example.png/840x560.webp">
</a>
</div>
```
Clients can recognize if an image was thumbnailed by its `src`
attribute starting with `/user_uploads/thumbnail/`. The `href` will
always link to the originally-uploaded file, at its original
resolution.
When a Zulip message is sent referencing an **uploaded image** in Markdown
image syntax, (e.g.,`![example image](/user_uploads/path/to/example.png)`),
Zulip will generate an image element with the following format:
```html
<img alt="example image" class="inline-image"
data-original-dimensions="1050x700"
data-original-content-type="image/png"
data-original-src="/user_uploads/path/to/example.png"
src="/user_uploads/thumbnail/path/to/example.png/840x560.webp">
```
Note that the Markdown image syntax is only supported/permitted for
uploaded images, not third-party image URLs.
As with link-derived image previews, clients can recognize if an image
was thumbnailed by its `src` attribute starting with
`/user_uploads/thumbnail/`. If an image is a thumbnail, the
`data-original-src` attribute will always reference the
originally-uploaded file, at its original resolution.
Note that images generated using Markdown image syntax may appear
inside arbitrary block-level elements, unlike the image previews from
links, which will always be top-level elements.
Regardless of which form (link-derived preview, or Markdown image
syntax), the `data-original-dimensions` and
`data-original-content-type` attributes will only be present if the
image was thumbnailed and the message was sent (or last edited)
after those attributes were added (see [Changes to image
formatting](#changes-to-image-formatting)). If the image is *not* a
thumbnail, clients should make a best-effort attempt to render the
given `src`, in a manner which minimizes layout shift when the
resource is loaded -- see the next section for a special case of this.
**Changes**: See [Changes to image formatting](#changes-to-image-formatting).
### Image-loading placeholders
If the server has yet to generate thumbnails for the image by the time
the message is sent, the `img` element will temporarily reference a
loading indicator image and have the `image-loading-placeholder`
class, which clients can use to identify loading indicators and
replace them with a more native loading indicator element if desired.
This spinner placeholder will have `data-original-dimensions`
and `data-original-content-type` attributes
if the message was sent (or last edited) after those attributes were added
(see [Changes to image formatting](#changes-to-image-formatting)).
In link-derived image previews, the placeholder is structured like this:
``` html
<div class="message_inline_image">
<a href="/user_uploads/path/to/example.png" title="example.png">
<img class="image-loading-placeholder"
data-original-dimensions="1920x1080"
data-original-content-type="image/png"
src="/path/to/spinner.png">
</a>
</div>
```
For image elements presented in Markdown image syntax, this placeholder
structure is used:
```html
<img alt="example image"
class="inline-image image-loading-placeholder"
data-original-content-type="image/png"
data-original-dimensions="1050x700"
data-original-src="/user_uploads/path/to/example.png"
src="/path/to/spinner.png">
```
Once the server has a working thumbnail, such messages will be updated
via an `update_message` event, with the `rendering_only: true` flag
(telling clients not to adjust message edit history), with appropriate
adjusted `rendered_content`. A client should process those events by
just using the updated rendering. If thumbnailing failed, the same
type of event will edit the message's rendered form to remove the
image preview element, so no special client-side logic should be
required to process such errors.
Note that in the uncommon situation that the thumbnailing system is
backlogged, an individual message containing multiple image previews
may be re-rendered multiple times as each image finishes thumbnailing
and triggers a message update.
Clients displaying message-edit history should rewrite image-loading
placeholder images in edit history to the generic deleted-file image
(`/static/images/errors/image-not-exist.png`).
### Transcoded images
Image elements whose formats are not widely supported by web browsers
(e.g., HEIC and TIFF) may contain a `data-transcoded-image` attribute,
which specifies a high-resolution thumbnail format that clients may
opt to present instead of the original image. If the
`data-transcoded-image` attribute is present, clients should use the
`data-original-content-type` attribute to decide whether to display the
original image or use the transcoded version.
Transcoded images are presented with this structure in image previews:
``` html
<div class="message_inline_image">
<a href="/user_uploads/path/to/example.heic" title="example.heic">
<img data-original-dimensions="1920x1080"
data-original-content-type="image/heic"
data-transcoded-image="1920x1080.webp"
src="/user_uploads/thumbnail/path/to/example.heic/840x560.webp">
</a>
</div>
```
Transcoded images presented in Markdown image syntax are structured like this:
```html
<img alt="example HEIC image" class="inline-image"
data-original-dimensions="1920x1080"
data-original-content-type="image/heic"
data-original-src="/user_uploads/path/to/example.heic"
data-transcoded-image="1920x1080.webp"
src="/user_uploads/thumbnail/path/to/example.heic/840x560.webp">
```
### Recommended client processing of image previews
Clients are recommended to do the following when processing image
previews:
- Clients that would like to use the image's aspect ratio to lay out
one or more images in the message feed may use the
`data-original-dimensions` attribute, which is present even if the
image is a placeholder spinner. This attribute encodes the
dimensions of the original image as `{width}x{height}`. These
dimensions are for the image as rendered, _after_ any EXIF rotation
and mirroring has been applied.
- If the client would like to control the thumbnail resolution used,
it can replace the final section of the URL (`840x560.webp` in the
example above) with the `name` of its preferred format from the set
of supported formats provided by the server in the
`server_thumbnail_formats` portion of the `register`
response. Clients should not make any assumptions about what format
the server will use as the "default" thumbnail resolution, as it may
change over time.
- Download button type elements should provide the original image
(encoded via the `href` of the containing `a` tag).
- The content-type of the original image is provided on a
`data-original-content-type` attribute, so clients can decide if
they are capable of rendering the original image.
- For images whose formats which are not widely-accepted by browsers
(e.g., HEIC and TIFF), the image may contain a
`data-transcoded-image` attribute, which specifies a high-resolution
thumbnail format which clients may use instead of the original
image.
- Lightbox elements for viewing an image should be designed to
immediately display any already-downloaded thumbnail while fetching
the original-quality image or an appropriate higher-quality
thumbnail from the server, to be transparently swapped in once it is
available. Clients that would like to size the lightbox based on the
size of the original image can use the `data-original-dimensions`
attribute, as described above.
- Animated images will have a `data-animated` attribute on the `img`
tag. As detailed in `server_thumbnail_formats`, both animated and
still images are available for clients to use, depending on their
preference. See, for example, the [web setting][help-previews]
to control whether animated images are autoplayed in the message
feed.
- Clients should not assume that the requested format is the format
that they will receive; in rare cases where the client has an
out-of-date list of `server_thumbnail_formats`, the server will
provide an approximation of the client's requested format. Because
of this, clients should not assume that the pixel dimensions or file
format match what they requested.
- No other processing of the URLs is recommended.
### Changes to image formatting
**In Zulip 12.0** (feature level 467), limited the Markdown
image syntax to only support uploaded images, not linking to
third-party image URLs.
**In Zulip 12.0** (feature level 437), added support for Markdown
image syntax, in addition to the previous link-derived image previews;
these can be inserted into any block-level element.
**In Zulip 10.0** (feature level 336), added
`data-original-content-type` attribute to convey the type of the
original image, and optional `data-transcoded-image` attribute for
images with formats which are not widely supported by browsers.
**In Zulip 9.2** (feature levels 278-279, and 287+), added
`data-original-dimensions` to the `image-loading-placeholder` spinner
images, containing the dimensions of the original image.
**In Zulip 9.0** (feature level 276), added `data-original-dimensions`
attribute to images that have been thumbnailed, containing the
dimensions of the full-size version of the image. Thumbnailing itself
was reintroduced at feature level 275.
Previously, with the exception of Zulip servers that used the beta
Thumbor-based implementation years ago, all image previews in Zulip
messages were not thumbnailed; the `a` tag and the `img` tag would both
point to the original image.
Clients that correctly implement the current API should handle
Thumbor-based older thumbnails correctly, as long as they do not
assume that `data-original-dimensions` is present. Clients should not
assume that messages sent prior to the introduction of thumbnailing
have been re-rendered to use the new format or have thumbnails
available.
## Video embeddings and previews
When a Zulip message is sent linking to an uploaded video, Zulip may
generate a video preview element with the following format. Supported
MIME types are `video/mp4`, `video/quicktime` (i.e., `.mov` files), and
`video/webm`. Because `video/quicktime` is not supported in every
browser, the preview element is hidden at render time when the browser
reports that it cannot play the video; the download link in the
surrounding `a` tag remains available.
``` html
<div class="message_inline_image message_inline_video">
<a href="/user_uploads/path/to/video.mp4">
<video preload="metadata" src="/user_uploads/path/to/video.mp4">
</video>
</a>
</div>
```
## Audio Players
When the Markdown media syntax is used with an uploaded file with an
audio `Content-Type`, Zulip will generate an HTML5 `<audio>` player
element. Supported MIME types are currently `audio/aac`, `audio/flac`,
`audio/mpeg`, and `audio/wav` (and its `audio/x-wav` and
`audio/vnd.wave` variants).
For example, `![file.mp3](/user_uploads/path/to/file.mp3)` renders as:
``` html
<audio controls preload="metadata"
src="/user_uploads/path/to/file.mp3" title="file.mp3">
</audio>
```
If the Zulip server has rewritten the URL of the audio file, it will
provide the URL in a `data-original-url` parameter. The Zulip server
does this for all non-uploaded file audio URLs.
``` html
<audio controls preload="metadata"
data-original-url="https://example.com/path/to/original/file.mp3"
src="https://zulipcdn.example.com/path/to/playable/file.mp3" title="file.mp3">
</audio>
```
Clients that cannot render an audio player are recommended to convert
audio elements into a link to the original URL.
The Zulip server does not validate whether uploaded files with an
audio `Content-Type` are actually playable.
**Changes**: New in Zulip 11.0 (feature level 405).
## Mentions and silent mentions
Zulip markup supports [mentioning](/help/mention-a-user-or-group)
users, user groups, and a few special "wildcard" mentions (the three
spellings of a channel wildcard mention: `@**all**`, `@**everyone**`,
`@**channel**` and the topic wildcard mention `@**topic**`).
Mentions result in a message being highlighted for the target user(s),
both in the UI and in notifications, and may also result in the target
user(s) following the conversation, [depending on their
settings](/help/follow-a-topic#follow-topics-where-you-are-mentioned).
Silent mentions of users or groups have none of those side effects,
but nonetheless uniquely identify the user or group
identified. (There's no such thing as a silent wildcard mention).
Permissions for mentioning users work as follows:
- Any user can mention any other user, though mentions by [muted
users](/help/mute-a-user) are automatically marked as read and thus do
not trigger notifications or otherwise get highlighted like unread
mentions.
- Wildcard mentions are permitted except where [organization-level
restrictions](/help/restrict-wildcard-mentions) apply.
- User groups can be mentioned if and only if the acting user is in
the `can_mention_group` group for that group. All user groups can be
silently mentioned by any user.
- System groups, when (silently) mentioned, should be displayed using
their description, not their `role:nobody` style API names; see the
main [system group
documentation](/api/group-setting-values#system-groups) for
details. System groups can only be silently mentioned right now,
because they happen to all use the empty `Nobody` group for
`can_mention_group`; clients should just use `can_mention_group` to
determine which groups to offer in typeahead in similar contexts.
- Requests to send or edit a message that are impermissible due to
including a mention where the acting user does not have permission to
mention the target will return an error. Mention syntax that does not
correspond to a real user or group is ignored.
Sample markup for `@**Example User**`:
``` html
<span class="user-mention" data-user-id="31">@Example User</span>
```
Sample markup for `@_**Example User**`:
``` html
<span class="user-mention silent" data-user-id="31">Example User</span>
```
Sample markup for `@**topic**`:
``` html
<span class="topic-mention">@topic</span>
```
Sample markup for `@**channel**`:
``` html
<span class="user-mention channel-wildcard-mention"
data-user-id="*">@channel</span>
```
Sample markup for `@*support*`, assuming "support" is a valid group:
``` html
<span class="user-group-mention"
data-user-group-id="17">@support</span>
```
Sample markup for `@_*support*`, assuming "support" is a valid group:
``` html
<span class="user-group-mention silent"
data-user-group-id="17">support</span>
```
Sample markup for `@_*role:administrators*`:
``` html
<span class="user-group-mention silent"
data-user-group-id="5">Administrators</span>
```
When processing mentions, clients should look up the user or group
referenced by ID, and update the textual name for the mention to the
current name for the user or group with that ID. Note that for system
groups, this requires special logic to look up the user-facing name
for that group; see [system
groups](/api/group-setting-values#system-groups) for details.
**Changes**: Prior to Zulip 10.0 (feature level 333), it was not
possible to silently mention [system
groups](/api/group-setting-values#system-groups).
In Zulip 9.0 (feature level 247), `channel` was added to the supported
[wildcard][help-mention-all] options used in the
[mentions][help-mentions] Markdown message formatting feature.
## Spoilers
**Changes**: In Zulip 3.0 (feature level 15), added
[spoilers][help-spoilers] to supported Markdown message formatting
features.
## Removed features
### Removed legacy Dropbox link preview markup
In Zulip 11.0 (feature level 395), the Zulip server stopped generating
legacy Dropbox link previews. Dropbox links are now previewed just
like standard Zulip image/link previews. However, some legacy Dropbox
previews may exist in existing messages.
Clients are recommended to prune these previews from message HTML;
since they always appear after the actual link, there is no loss of
information/functionality. They can be recognized via the classes
`message_inline_ref`, `message_inline_image_desc`, and
`message_inline_image_title`:
``` html
<div class="message_inline_ref">
<a href="https://www.dropbox.com/sh/cm39k9e04z7fhim/AAAII5NK-9daee3FcF41anEua?dl=" title="Saves">
<img src="/path/to/folder_dropbox.png">
</a>
<div><div class="message_inline_image_title">Saves</div>
<desc class="message_inline_image_desc"></desc>
</div>
</div>
```
### Removed legacy avatar markup
In Zulip 4.0 (feature level 24), the rarely used `!avatar()`
and `!gravatar()` markup syntax, which was never documented and had an
inconsistent syntax, were removed.
## Related articles
* [Markdown formatting](/help/format-your-message-using-markdown)
* [Send a message](/api/send-message)
* [Render a message](/api/render-message)
[help-code]: /help/code-blocks
[help-emoji]: /help/emoji-and-emoticons
[help-custom-emoji]: /help/custom-emoji
[help-playgrounds]: /help/code-blocks#code-playgrounds
[help-spoilers]: /help/spoilers
[help-global-time]: /help/global-times
[help-mentions]: /help/mention-a-user-or-group
[help-mention-all]: /help/mention-a-user-or-group#mention-everyone-on-a-channel
[help-previews]: /help/image-video-and-website-previews#configure-how-animated-images-are-played

1
api_docs/missing.md Normal file
View File

@@ -0,0 +1 @@
No such article.

View File

@@ -0,0 +1,225 @@
# Mobile notifications
Zulip Server 11.0+ supports end-to-end encryption (E2EE) for mobile
push notifications. Mobile push notifications sent by all Zulip
servers go through Zulip's mobile push notifications service, which
then delivers the notifications through the appropriate
platform-specific push notification service (Google's FCM or Apple's
APNs). E2EE push notifications ensure that mobile notification message
content and metadata is not visible to intermediaries.
Mobile clients that have [registered an E2EE push
device](/api/register-push-device) will receive mobile notifications
end-to-end encrypted by their Zulip server.
This page documents the format of the encrypted JSON-format payloads
that the client will receive through this protocol. The same encrypted
payload formats are used for both Firebase Cloud Messaging (FCM) and
Apple Push Notification service (APNs).
## Payload examples
### New channel message
Sample JSON data that gets encrypted:
```json
{
"channel_id": 10,
"channel_name": "Denmark",
"content": "@test_user_group",
"mentioned_user_group_id": 41,
"mentioned_user_group_name": "test_user_group",
"message_id": 45,
"realm_name": "Zulip Dev",
"realm_url": "http://zulip.testserver",
"recipient_type": "channel",
"sender_avatar_url": "https://secure.gravatar.com/avatar/818c212b9f8830dfef491b3f7da99a14?d=identicon&version=1",
"sender_full_name": "aaron",
"sender_id": 6,
"time": 1754385395,
"topic": "test",
"type": "message",
"user_id": 10
}
```
- The `mentioned_user_group_id` and `mentioned_user_group_name` fields
are only present for messages that mention a group containing the
current user, and triggered a mobile notification because of that
group mention. For example, messages that mention both the user
directly and a group containing the user, these fields will not be
present in the payload, because the direct mention has precedence.
**Changes**: New in Zulip 11.0 (feature level 413).
### New direct message
Sample JSON data that gets encrypted:
```json
{
"content": "test content",
"message_id": 46,
"realm_name": "Zulip Dev",
"realm_url": "http://zulip.testserver",
"recipient_type": "direct",
"recipient_user_ids": [6,10,12,15],
"sender_avatar_url": "https://secure.gravatar.com/avatar/818c212b9f8830dfef491b3f7da99a14?d=identicon&version=1",
"sender_full_name": "aaron",
"sender_id": 6,
"time": 1754385290,
"type": "message",
"user_id": 10
}
```
- The `recipient_user_ids` field is a sorted array of all user IDs in
the direct message conversation, including both `user_id` and
`sender_id`.
**Changes**: In Zulip 12.0 (feature level 429), replaced the
`pm_users` field with `recipient_user_ids`. The old `pm_users` field
was only present for group DMs, and was a string containing a
comma-separated list of sorted user IDs.
New in Zulip 11.0 (feature level 413).
### Remove notifications
When a batch of messages that had previously been included in mobile
notifications are marked as read, are deleted, become inaccessible, or
otherwise should no longer be displayed to the user, a removal
notification is sent.
Sample JSON data that gets encrypted:
```json
{
"message_ids": [
31,
32
],
"realm_name": "Zulip Dev",
"realm_url": "http://zulip.testserver",
"type": "remove",
"user_id": 10
}
```
[zulip-bouncer]: https://zulip.readthedocs.io/en/latest/production/mobile-push-notifications.html#mobile-push-notification-service
**Changes**: New in Zulip 11.0 (feature level 413).
### Test push notification
A user can trigger [sending an E2EE test push notification](/api/e2ee-test-notify)
to the user's selected mobile device or all of their mobile devices.
Sample JSON data that gets encrypted:
```json
{
"realm_name": "Zulip Dev",
"realm_url": "http://zulip.testserver",
"time": 1754577820,
"type": "test",
"user_id": 10
}
```
**Changes**: New in Zulip 11.0 (feature level 420).
### Data sent to Zulip's push notifications service
Sample JSON data sent by a self-hosted server to the Zulip's push notifications service:
```json
{
"realm_uuid": "e502dde1-74fc-44b3-9e3a-114c41ed3ea4",
"push_requests": [
{
"token_id": "AAAAAAAAAAE=",
"http_headers": {
"apns_priority": 10,
"apns_push_type": "alert"
},
"payload": {
"push_key_id": 10,
"encrypted_data": "uOGQ9m8bdnLab/2Qq6WLdJnFUsU/NlX0955rF6GgpiZylQB/HSD+lrHct0KUXdCneu+fnGOuBMAGkYol+SLlbvdsnePn/f6wSvMDbm3iffcgiz2u8TywUlmQL/Q7Ruj5RSpLgEhpFitL/WjwQBtrA31vsqMHycmROju+tOhFlVjmzJmYy3o7ZQDi/YeB2Y+CnA5EuuXjckBYSjL4vi/YaEJXmeHvJ8Pk3T/WwXvo8CFZYlafiqSw0vC/2bkjPTFFAFVo/49nAUI+5Rpa90wJUVChsrkKTclOs4Ih1dNIDYr6+WoIKJTtIR9zgDg3YOkVHBZhlt7Se3i40WAs5JAb1PViMpAp2hbU36z1Qq0g90nmfRjXN9FRdAPaKlbFTT2PkEtS9wVBv9T14ufkhbOwaMLfx5iaHKw3XHoWo7Fe+0IF9ZJ77uhCZoA1kyFKDhl7AZ8K4DOvib8gsfkeAR4XXXnXVmLtAyjBhMrWYNsECo9j4UeE6M90z3xIVR8=",
"aps": {
"mutable-content": 1,
"alert": {
"title": "New notification"
}
}
}
},
{
"token_id": "AAAAAAAAAAI=",
"fcm_priority": "high",
"payload": {
"push_key_id": 20,
"encrypted_data": "OzPhtLiyU1U+3ynqyTxkFt83N5GN7t3Uw8/OkCoFKFo/cu3GAzCMMbAAhPghflkrFK37SNOuxpPiL1TzPy5tQJqdSKpQrgu6cp0Y6VVA1aV/zsCDAcSABaWeaOeC5mVL+xFpmFeEbhzUaOLchbRn4kBO4m8gqDU/rAn0cKFY1F7tyCgC+fvvcczP05itDLpkwZMnrADGp3tSHFldr4iGO1pWJxFTXFFhg63UyH1FcMXKFzBPek7hLbpLsqu5OFEQv2TtDbAYdWZr1LXRqnkHTDmMd6NAdkOsVcnk31jHThFPDqaM5zDXb24hGHW79OpBnGAQWydfeChS4pC4yHWCO6ZRDqwvJX9IydS+V7S91KCl0QSToaXvgW7Q3zvHunzu7L/rw0dQQRgPM3qIOHr7gGtptkZpmKuT6icdDGgjRtgP/L0TfxdRKa37fn6nF64+HH60wLPYWOz7vZjgTrA20MrbA3ogMfhFYpwjppidFGVWjrLpk+peQjHB1sY="
}
}
]
}
```
**Changes**: In Zulip 12.0 (feature level 468), the `device_id` and
`push_account_id` fields were replaced with `token_id` and `push_key_id`
to support the rotation of tokens provided by FCM/APNs and keys used
to encrypt push notifications.
New in Zulip 11.0 (feature level 413).
### Data sent to FCM
Zulip's push notifications service uses [Firebase Admin Python SDK](https://github.com/firebase/firebase-admin-python)
to access FCM.
A sample `messages` argument, which is internally used by the SDK to prepare payload for FCM,
passed to [`firebase_admin.messaging.send_each`](https://firebase.google.com/docs/reference/admin/python/firebase_admin.messaging#send_each):
```py
[
firebase_admin.messaging.Message(
data={
'push_key_id': '20',
'encrypted_data': 'OzPhtLiyU1U+3ynqyTxkFt83N5GN7t3Uw8/OkCoFKFo/cu3GAzCMMbAAhPghflkrFK37SNOuxpPiL1TzPy5tQJqdSKpQrgu6cp0Y6VVA1aV/zsCDAcSABaWeaOeC5mVL+xFpmFeEbhzUaOLchbRn4kBO4m8gqDU/rAn0cKFY1F7tyCgC+fvvcczP05itDLpkwZMnrADGp3tSHFldr4iGO1pWJxFTXFFhg63UyH1FcMXKFzBPek7hLbpLsqu5OFEQv2TtDbAYdWZr1LXRqnkHTDmMd6NAdkOsVcnk31jHThFPDqaM5zDXb24hGHW79OpBnGAQWydfeChS4pC4yHWCO6ZRDqwvJX9IydS+V7S91KCl0QSToaXvgW7Q3zvHunzu7L/rw0dQQRgPM3qIOHr7gGtptkZpmKuT6icdDGgjRtgP/L0TfxdRKa37fn6nF64+HH60wLPYWOz7vZjgTrA20MrbA3ogMfhFYpwjppidFGVWjrLpk+peQjHB1sY=',
},
token='push-device-token-3',
android=firebase_admin.messaging.AndroidConfig(priority='high'),
),
]
```
**Changes**: In Zulip 12.0 (feature level 468), the `push_account_id`
field was replaced with `push_key_id` to support the rotation of
keys used to encrypt push notifications.
New in Zulip 11.0 (feature level 413).
### Data sent to APNs
Zulip's push notifications service uses [aioapns](https://github.com/Fatal1ty/aioapns) to access APNs.
A sample `request` argument, which is internally used by the library to prepare payload for APNs,
passed to [`aioapns.APNs.send_notification`](https://github.com/Fatal1ty/aioapns/blob/96831003ec5a8986206cde77e59fdb4b5a3c4b24/aioapns/client.py):
```py
aioapns.NotificationRequest(
apns_topic='remote_push_device_ios_app_id',
device_token='push-device-token-1',
message={
'push_key_id': 10,
'encrypted_data': 'rUNqoWOB+EQmjThJyXhDptmUrHyzSx4DPlvShzrM7XGdRVMG5qNuH0dnGQDVza9frnWNVOF3vFcuYvDnUnYRBf1j+/n1ML1K2CBnsThCGl3KJNWrKcf5fME7Q1dU2xtJ3+RAKuLtZ9y2gq6DWamui7WfQ75m1eJpYRDbbHIQEiSIZpo7X2Lie3aHkQBgE8SN5MJ6N3VM33DM6i1xGpIeWiFy+hqNloGyEI2qf6xV0SjvvkN+HbGticben4atBkAuAIKi0gIYMPyMihH26T1sEhOH3IDyO3KvaHe1NIdj0naT9RoFkN5UgdxIchXQ7qkVEjivA2E/HefpvZYlhems6TAosfJwgCMB8HuydqdImjixkugRQfugroTTG97p6xQIJSFWCOyrpuBDElI0Ale8XjmzaVo4Dbgqz5kIAhmJWtlwgJw8nt7Orr3EWUVjnIAi0nHCFObAXNShedAbyuLeC1qezqC4FZe/GOLLi4DPWgWSdk8PV5vGw9YC+XcZ38dqQogtpG7dpzMwwsqzLBmlzQ==',
'aps': {
'mutable-content': 1,
'alert': {'title': 'New notification'}
}
},
priority=10,
push_type="alert",
)
```
**Changes**: In Zulip 12.0 (feature level 468), the `push_account_id`
field was replaced with `push_key_id` to support the rotation of
keys used to encrypt push notifications.
New in Zulip 11.0 (feature level 413).

View File

@@ -0,0 +1,106 @@
# Outgoing webhook payloads
Zulip supports [outgoing webhooks](/help/outgoing-webhooks) in a clean,
native [Zulip format](#zulip-format), as well as in a [Slack-compatible
format](#slack-compatible-format).
## Zulip format
{generate_code_example|/zulip-outgoing-webhook:post|fixture}
### Fields documentation
{generate_return_values_table|zulip.yaml|/zulip-outgoing-webhook:post}
## Slack-compatible format
This webhook format is compatible with [Slack's outgoing webhook
API](https://api.slack.com/custom-integrations/outgoing-webhooks),
which can help with porting an existing Slack integration to work with
Zulip, and allows immediate integration with many third-party systems
that already support Slack outgoing webhooks.
The following table details how the Zulip server translates a Zulip
message into the Slack-compatible webhook format.
<table class="table">
<thead>
<tr>
<th>Name</th>
<th>Description</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>token</code></td>
<td>A string of alphanumeric characters you can use to
authenticate the webhook request (each bot user uses a fixed token)</td>
</tr>
<tr>
<td><code>team_id</code></td>
<td>ID of the Zulip organization prefixed by "T".</td>
</tr>
<tr>
<td><code>team_domain</code></td>
<td>Hostname of the Zulip organization</td>
</tr>
<tr>
<td><code>channel_id</code></td>
<td>Channel ID prefixed by "C"</td>
</tr>
<tr>
<td><code>channel_name</code></td>
<td>Channel name</td>
</tr>
<tr>
<td><code>thread_ts</code></td>
<td>Timestamp for when message was sent</td>
</tr>
<tr>
<td><code>timestamp</code></td>
<td>Timestamp for when message was sent</td>
</tr>
<tr>
<td><code>user_id</code></td>
<td>ID of the user who sent the message prefixed by "U"</td>
</tr>
<tr>
<td><code>user_name</code></td>
<td>Full name of sender</td>
</tr>
<tr>
<td><code>text</code></td>
<td>The content of the message (in Markdown)</td>
</tr>
<tr>
<td><code>trigger_word</code></td>
<td>Trigger method</td>
</tr>
<tr>
<td><code>service_id</code></td>
<td>ID of the bot user</td>
</tr>
</tbody>
</table>
The above data is posted as list of tuples (not JSON), here's an example:
```
[('token', 'v9fpCdldZIej2bco3uoUvGp06PowKFOf'),
('team_id', 'T1512'),
('team_domain', 'zulip.example.com'),
('channel_id', 'C123'),
('channel_name', 'integrations'),
('thread_ts', 1532078950),
('timestamp', 1532078950),
('user_id', 'U21'),
('user_name', 'Full Name'),
('text', '@**test**'),
('trigger_word', 'mention'),
('service_id', 27)]
```
* For successful requests, if data is returned, it returns that data,
else it returns a blank response.
* For failed requests, it returns the reason of failure, as returned by
the server, or the exception message.

View File

@@ -0,0 +1,60 @@
# Real-time events API
Zulip's real-time events API lets you write software that reacts
immediately to events happening in Zulip. This API is what powers the
real-time updates in the Zulip web and mobile apps. As a result, the
events available via this API cover all changes to data displayed in
the Zulip product, from new messages to channel descriptions to
emoji reactions to changes in user or organization-level settings.
## Using the events API
The simplest way to use Zulip's real-time events API is by using
`call_on_each_event` from our Python bindings. You just need to write
a Python function (in the examples below, the `lambda`s) and pass it
into `call_on_each_event`; your function will be called whenever a new
event matching the specified parameters (`event_types`, `narrow`,
etc.) occurs in Zulip.
`call_on_each_event` takes care of all the potentially tricky details
of long-polling, error handling, exponential backoff in retries, etc.
It's cousin, `call_on_each_message`, provides an even simpler
interface for processing Zulip messages.
More complex applications (like a Zulip terminal client) may need to
instead use the raw [register](/api/register-queue) and
[events](/api/get-events) endpoints.
## Usage examples
{start_tabs}
{tab|python}
```
#!/usr/bin/env python
import sys
import zulip
# Pass the path to your zuliprc file here.
client = zulip.Client(config_file="~/zuliprc")
# Print every message the current user would receive
# This is a blocking call that will run forever
client.call_on_each_message(lambda msg: sys.stdout.write(str(msg) + "\n"))
# Print every event relevant to the user
# This is a blocking call that will run forever
client.call_on_each_event(lambda event: sys.stdout.write(str(event) + "\n"))
```
{end_tabs}
## Parameters
You may also pass in the following keyword arguments to `call_on_each_event`:
{generate_api_arguments_table|zulip.yaml|/real-time:post}
See the [GET /events](/api/get-events) documentation for
more details on the format of individual events.

View File

@@ -0,0 +1,64 @@
# Error handling
Zulip's API will always return a JSON format response.
The HTTP status code indicates whether the request was successful
(200 = success, 4xx = user error, 5xx = server error).
Every response, both success and error responses, will contain at least
two keys:
- `msg`: an internationalized, human-readable error message string.
- `result`: either `"error"` or `"success"`, which is redundant with the
HTTP status code, but is convenient when print debugging.
Every error response will also contain an additional key:
- `code`: a machine-readable error string, with a default value of
`"BAD_REQUEST"` for general errors.
Clients should always check `code`, rather than `msg`, when looking for
specific error conditions. The string values for `msg` are
internationalized (e.g., the server will send the error message
translated into French if the user has a French locale), so checking
those strings will result in buggy code.
!!! tip ""
If a client needs information that is only present in the string value
of `msg` for a particular error response, then the developers
implementing the client should [start a conversation here][api-design]
in order to discuss getting a specific error `code` and/or relevant
additional key/value pairs for that error response.
In addition to the keys described above, some error responses will
contain other keys with further details that are useful for clients. The
specific keys present depend on the error `code`, and are documented at
the API endpoints where these particular errors appear.
**Changes**: Before Zulip 5.0 (feature level 76), all error responses
did not contain a `code` key, and its absence indicated that no specific
error `code` had been allocated for that error.
## Common error responses
Documented below are some error responses that are common to many
endpoints:
{generate_code_example|/rest-error-handling:post|fixture}
## Ignored Parameters
In JSON success responses, all Zulip REST API endpoints may return
an array of parameters sent in the request that are not supported
by that specific endpoint.
While this can be expected, e.g., when sending both current and legacy
names for a parameter to a Zulip server of unknown version, this often
indicates either a bug in the client implementation or an attempt to
configure a new feature while connected to an older Zulip server that
does not support said feature.
{generate_code_example|/settings:patch|fixture}
[api-design]: https://chat.zulip.org/#narrow/channel/378-api-design

32
api_docs/rest.md Normal file
View File

@@ -0,0 +1,32 @@
# The Zulip REST API
The Zulip REST API powers the Zulip web and mobile apps, so anything
you can do in Zulip, you can do with Zulip's REST API. To use this API:
* You'll need to [get an API key](/api/api-keys). You will likely
want to [create a bot](/help/add-a-bot-or-integration), unless you're
using the API to interact with
your own account (e.g., exporting your personal message history).
* Choose what language you'd like to use. You can download the
[Python or JavaScript bindings](/api/installation-instructions), projects in
[other languages](/api/client-libraries), or
just make HTTP requests with your favorite programming language.
* If you're making your own HTTP requests, you'll want to send the
appropriate [HTTP basic authentication headers](/api/http-headers).
* The Zulip API has a standard
[system for reporting errors](/api/rest-error-handling).
Most other details are covered in the documentation for the individual
endpoints:
!!! tip ""
You may use the `client.call_endpoint` method of our Python API
bindings to call an endpoint that isn't documented here. For an
example, see [Upload a custom emoji](/api/upload-custom-emoji).
{!rest-endpoints.md!}
Since Zulip is open source, you can also consult the
[Zulip server source code](https://github.com/zulip/zulip/) as a
workaround for how to do anything not documented here.

View File

@@ -0,0 +1,121 @@
# Roles and permissions
Zulip offers several levels of permissions based on a
[user's role](/help/user-roles) in a Zulip organization.
Here are some important details to note when working with these
roles and permissions in Zulip's API:
## A user's role
A user's account data include a `role` property, which contains the
user's role in the Zulip organization. These roles are encoded as:
* Organization owner: 100
* Organization administrator: 200
* Organization moderator: 300
* Member: 400
* Guest: 600
User account data also include these boolean properties that duplicate
the related roles above:
* `is_owner` specifying whether the user is an organization owner.
* `is_admin` specifying whether the user is an organization administrator.
* `is_guest` specifying whether the user is a guest user.
These are intended as conveniences for simple clients, and clients
should prefer using the `role` field, since only that one is updated
by the [events API](/api/get-events).
Note that [`POST /register`](/api/register-queue) also returns an
`is_moderator` boolean property specifying whether the current user is
at least an organization moderator. The property will be true for admins
and owners too.
### User account data in the API
Endpoints that return the user account data / properties mentioned
above are:
* [`GET /users`](/api/get-users)
* [`GET /users/{user_id}`](/api/get-user)
* [`GET /users/{email}`](/api/get-user-by-email)
* [`GET /users/me`](/api/get-own-user)
* [`GET /events`](/api/get-events)
* [`POST /register`](/api/register-queue)
Note that the [`POST /register` endpoint](/api/register-queue) returns
the above boolean properties to describe the role of the current user,
when `realm_user` is present in `fetch_event_types`.
Additionally, the specific events returned by the
[`GET /events` endpoint](/api/get-events) containing data related
to user accounts and roles are the [`realm_user` add
event](/api/get-events#realm_user-add), and the
[`realm_user` update event](/api/get-events#realm_user-update).
## Permission levels
Many areas of Zulip are customizable by the roles
above, such as (but not limited to) [restricting message editing and
deletion](/help/restrict-message-editing-and-deletion) and various
permissions for different [channel types](/help/channel-permissions).
The potential permission levels are:
* Everyone / Any user including Guests (least restrictive)
* Members
* Full members
* Moderators
* Administrators
* Owners
* Nobody (most restrictive)
These permission levels and policies in the API are designed to be
cutoffs in that users with the specified role and above have the
specified ability or access. For example, a permission level documented
as 'moderators only' includes organization moderators, administrators,
and owners.
Note that specific settings and policies in the Zulip API that use these
permission levels will likely support a subset of those listed above.
## Group-based permissions
Some settings have been migrated to a more flexible system based on
[user groups](/api/group-setting-values).
## Determining if a user is a full member
When a Zulip organization has set up a [waiting period before new members
turn into full members](/help/restrict-permissions-of-new-members),
clients will need to determine if a user's account has aged past the
organization's waiting period threshold.
The `realm_waiting_period_threshold`, which is the number of days until
a user's account is treated as a full member, is returned by the
[`POST /register` endpoint](/api/register-queue) when `realm` is present
in `fetch_event_types`.
Clients can compare the `realm_waiting_period_threshold` to a user
accounts's `date_joined` property, which is the time the user account
was created, to determine if a user has the permissions of a full
member or a new member.

79
api_docs/send-message.md Normal file
View File

@@ -0,0 +1,79 @@
{generate_api_header(/messages:post)}
## Usage examples
{start_tabs}
{generate_code_example(python)|/messages:post|example}
{generate_code_example(javascript)|/messages:post|example}
{tab|curl}
{!curl-auth-credentials.md!}
``` curl
# For channel messages
curl -X POST {{ api_url }}/v1/messages \
-u EMAIL_ADDRESS:API_KEY \
--data-urlencode type=stream \
--data-urlencode 'to="Denmark"' \
--data-urlencode topic=Castle \
--data-urlencode 'content=I come not, friends, to steal away your hearts.'
# For direct messages
curl -X POST {{ api_url }}/v1/messages \
-u EMAIL_ADDRESS:API_KEY \
--data-urlencode type=direct \
--data-urlencode 'to=[9]' \
--data-urlencode 'content=With mirth and laughter let old wrinkles come.'
```
{tab|zulip-send}
You can use `zulip-send`
(available after you `pip install zulip`) to easily send Zulips from
the command-line, providing the message content via STDIN.
```bash
# For channel messages
zulip-send --stream Denmark --subject Castle \
--user othello-bot@example.com --api-key a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5
# For direct messages
zulip-send hamlet@example.com \
--user othello-bot@example.com --api-key a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5
```
#### Passing in the message on the command-line
If you'd like, you can also provide the message on the command-line with the
`-m` or `--message` flag, as follows:
```bash
zulip-send --stream Denmark --subject Castle \
--message 'I come not, friends, to steal away your hearts.' \
--user othello-bot@example.com --api-key a0b1c2d3e4f5a6b7c8d9e0f1a2b3c4d5
```
You can omit the `user` and `api-key` parameters if you have a `~/.zuliprc`
file.
{end_tabs}
## Parameters
{generate_api_arguments_table|zulip.yaml|/messages:post}
{generate_parameter_description(/messages:post)}
## Response
{generate_return_values_table|zulip.yaml|/messages:post}
{generate_response_description(/messages:post)}
#### Example response(s)
{generate_code_example|/messages:post|fixture}

14
api_docs/sidebar_index.md Normal file
View File

@@ -0,0 +1,14 @@
* [Overview](/api/rest)
* [Installation instructions](/api/installation-instructions)
* [API keys and zuliprc files](/api/api-keys)
* [Configuring the Python bindings](/api/configuring-python-bindings)
* [HTTP headers](/api/http-headers)
* [Error handling](/api/rest-error-handling)
* [Roles and permissions](/api/roles-and-permissions)
* [Group-setting values](/api/group-setting-values)
* [Message formatting](/api/message-formatting)
* [Zulip URLs](/api/zulip-urls)
* [Client libraries](/api/client-libraries)
* [API changelog](/api/changelog)
{!rest-endpoints.md!}

109
api_docs/zulip-urls.md Normal file
View File

@@ -0,0 +1,109 @@
# Zulip URLs
This page details how to properly construct and parse the URLs that
the Zulip web app uses for various types of views.
Because other clients needs to be able to resolve and process these
links in order to implement equivalent behavior that navigates
directly in say the mobile apps, it's important to have a clear
specification of exactly how these URLs work.
Essentially all of the data is encoded in the URL fragment (`#`) part
of a URL; the protocol, host and path will just be the canonical URL
for the Zulip server (In these examples,
`https://zulip.example.com/`).
## Message feed views
Most links in Zulip are to message feed views, and for that reason
these have the most developed syntax and legacy behavior.
Message feed URLs always start with `#narrow/`, follow by one or more
[search operator/operand pairs](/api/construct-narrow), separated by
`/`s. The operator may be negated by putting a `-` at the start of
it. For example:
`https://zulip.example.com/#narrow/is/starred/sender/17/-channel/14`
is the feed of starred messages sent by user ID to everywhere but
channel 14. The search documentation covers the valid operators and
their meaning.
See also the relevant [message formatting
documentation](/api/message-formatting) for details on Markdown
representations of Zulip-internal links that will be translated into
HTML containing links that use these URLs.
Here, we describe some special encoding rules.
### Operand encoding and decoding
Strings in operands are URL-encoded, and then additional substitution
rules are applied to avoid over-zealous browser handling of certain
characters in the URL fragment:
- `%` => `.`
- `(` => `.28`
- `)` => `.29`
- `.` => `.2E`
They can decoded by applying the reverse transformation: Replace all
`.` characters with `%`, and then do standard URL-decoding.
### Encoding channels
Channel operands must be encoded in one of the two modern fully
supported formats:
- `42`: Just the ID of the channel. Clients should simply parse the
channel ID to look up the channel, which is of course not guaranteed
to be accessible to the acting user or even exist.
- `42-channel-name`. The ID of the channel, with a human-readable hint
of the channel name. Clients generating Zulip URLs are recommended
to include channel name hints where there is a readable URL-encoding
of the channel name, but to skip doing so for channel names written
in non-ascii languages or where otherwise the slug would not make
the URL nicer for humans. Clients must parse this format by
discarding everything after the `-` and treating it identically to
the simpler integer-only format. Note that means nothing enforces
that the string have anything to do with the channel name;
functionally, it just an optional hint.
These two formats allow Zulip URLs to stably refer to a specific
channel, even though channels can be renamed, while still allowing the
URLs to have user-friendly name hints most of the time.
There is an additional legacy format that was used prior to 2018 that
clients are required to support:
- `channel-name`: Legacy format of just the channel name, URL-encoded
and with spaces replaced with dashes. The legacy format should never
take precedence over the modern format, so a link with
`2016-election` as the slug must be parsed as the channel with ID
2016, even if theoretically it could have been originally intended
as referring to a channel named `2016 election`.
Clients are not recommended to ever generate this legacy format.
## zulip:// links for mobile login
Zulip's single-sign on login process for the mobile app ends with a
redirect to `zulip://login` with the following query parameters:
- `email`: The email address for the authenticated account.
- `otp_encrypted_api_key`: The API key for the client, encrypted using
the `mobile_flow_otp` that the client provided when initiating the
login attempt.
- `realm`: The full URL of the Zulip organization.
- `user_id`: The Zulip user ID for the authenticated account.
**Changes**: The `user_id` field was added to the set of included
query parameters in Zulip 5.0 (feature level 128).
## Related articles
* [Message formatting API](/api/message-formatting)
* [Construct a narrow](/api/construct-narrow) for search.
* [Markdown formatting help](/help/format-your-message-using-markdown)
* [Send a message](/api/send-message)