WebSocket based API to connect to Zello channels
Version 1.0
This document is intended for developers interested in implementation of their own Zello Channel API client connecting to Zello channels. If you want integrate Zello into your iOS or Android app, check out the mobile SDKs instead.
This API supports subset of Zello features and currently focused on sending and receiving channel voice messages. See Supported features for the complete list.
To access the API you will need valid account credentials and/or a valid access token, based on the JWT standard. See Authentication.
Service | WebSocket URL |
---|---|
Consumer Zello | wss://zello.io/ws |
Zello Work | wss://zellowork.io/ws/network name |
Zello Enterprise Server | wss://your server domain /ws/mesh |
Note that the protocol only supports secure connections over TLS.
The API supports two types of accounts:
Anonymous accounts:
- No need to provide username or password
- Can access unrestricted channels in listen only mode
- Only supported with consumer Zello
- A valid auth token is required
Named accounts:
- Must include a valid username and password
- Have full access to authorized channels
- Supported for both Zello Work and consumer Zello
- A valid auth token is required for consumer Zello
The API monitors connectivity by sending a WebSocket Ping frame to the client every 30 seconds. The WebSocket client must respond to the Ping frame with a Pong frame. If a client takes longer than 30 seconds to respond with a Pong frame, the API terminates the connection.
This API uses persistent WebSocket connection with JSON-formatted WebSocket text messages for control protocol and WebSocket binary messages for voice data.
Each control request contains a command and an optional sequence number.
command
Command nameseq
Sequence number
A sequence number is required only if a response is expected. Both server and client maintain their own counters to ensure that unique sequence numbers are used with commands that include a sequence number.
Authenticates the client and connects to channels. This must be the first command the client sends after establishing WebSocket connection. To stop the session and disconnect from the channels simply close the connection.
Connecting to multiple channels (up to 100) is currently supported for Zello Work only.
Name | Type | Value / Description |
---|---|---|
command |
string | logon |
seq |
integer | Command sequence number |
auth_token |
string | (optional) API authentication token. If omitted refresh_token is required when connecting to consumer Zello. See Authentication |
refresh_token |
string | (optional) API refresh token. If omitted auth_token is required when connecting to consumer Zello. See Authentication |
username |
string | (optional) Username to logon with. If not provided the client will connect anonymously. See Authentication |
password |
string | (optional) Password to logon with. Required if username is provided. |
channels |
array of strings | The list of names of the channels to connect to. |
listen_only |
boolean | (optional) Set to true to connect in listen-only mode. |
version |
string | (optional) Client version string. If not provided, the server will use the Channel API server version. |
platform_type |
string | (optional) Client platform type, any string |
platform_name |
string | (optional) Client platform name, any string. If includes Gateway or Kiosk (case-insensitive), the Zello Alarms service will track the online status of this client. |
{
"command": "logon",
"seq": 1,
"auth_token": "[json web token]",
"username": "sherlock",
"password": "secret",
"channels": ["Baker Street 221B", "Reichenbach Falls"]
}
{
"seq": 1,
"success": true,
"refresh_token": "[refresh json web token]"
}
or
{
"seq": 1,
"error": "error code"
}
A successful response includes refresh_token
which can be used to quickly reconnect if the WebSocket connection is broken due to brief network interruption.
images_supported
flag indicates channel will accept images. texting_supported
flag indicates if channel will accept text messages. locations_supported
flag indicates if channel will accept locations.
Value | Description |
---|---|
not enough params |
The request is missing required parameters, such as token or username/password |
not authorized |
The logon fails due to invalid credentials |
internal server error |
There are any unexpected server side failures; an immediate retry may or may not succeed |
channels limit exceeded |
The list of channels supplied is longer than supported by the API. |
After successfully connecting to the channel and receiving channel status you can start sending voice messages. Each message is sent as stream, which begins with start_stream
command followed by the sequence of binary packets with audio data and ends with stop_stream
command. Zello uses Opus voice codec to compress audio stream.
Starts a new stream to the channel. The successful response includes stream_id
which must be used in all data packets for this message as well as in stop_stream
command.
Name | Type | Value / Description |
---|---|---|
command |
string | start_stream |
seq |
integer | Command sequence number |
channel |
string | The channel to send the message to |
type |
string | Stream type. Only audio is currently supported |
codec |
string | The name of audio codec used. Required for audio streams. Must be opus . |
codec_header |
string | base64-encoded string, representing audio encoding parameters. Required for audio streams. See below |
packet_duration |
integer | Audio packet duration in milliseconds. Values between 2.5 ms and 60 ms are supported. |
for |
string | Optional username to send message to. Other users in the channel won't be receiving this message |
codec_header
is base64-encoded 4 byte array, which represents audio encoding attributes used for the message being sent:
{sample_rate_hz(16LE), frames_per_packet(8), frame_size_ms(8)}
Byte | Value | Description |
---|---|---|
0 & 1 | sample_rate_hz |
16 bit little-endian value of audio sample rate in Hz |
2 | frames_per_packet |
Number of frames per packet (1 or 2) |
3 | frame_size_ms |
Audio frame size in milliseconds |
Example: value of gD4BPA==
in base64 decodes to {0x80, 0x3e, 0x01, 0x3c}
which represents 16000 Hz sample rate, 1 frame per packet, 60 ms frame size. See example implementation.
{
"command": "start_stream",
"seq": 2,
"channel": "Baker Street 221B",
"type": "audio",
"codec": "opus",
"codec_header": "gD4BPA==",
"packet_duration": 20
}
or
{
"command": "start_stream",
"seq": 2,
"channel": "Baker Street 221B",
"type": "audio",
"codec": "opus",
"codec_header": "gD4BPA==",
"packet_duration": 20,
"for": "mrs.hudson"
}
{
"seq": 2,
"success": true,
"stream_id": 22695
}
Stops outgoing stream. Send this command after you sent the last data packet.
Name | Type | Value / Description |
---|---|---|
command |
string | stop_stream |
seq |
integer | Command sequence number |
stream_id |
integer | Stream ID as returned in response to start_stream command |
channel |
string | The channel to send the message to |
{
"command": "stop_stream",
"seq": 3,
"stream_id": 22695,
"channel": "Baker Street 221B"
}
The same binary packet structure is used for any streamed data (e.g. audio) travelling both ways. The packet_id
field is populated with the packet number for the audio packets sent from the server to a client. When streaming data to the server the packet_id
value is ignored and should be filled with zeroes. Fields are stored in network byte order.
{type(8) = 0x01, stream_id(32), packet_id(32), data[]}
After successfully connecting to the channel and receiving channel status you can start sending images.
If channel does not support image messaging you will receive an error for send_image
command.
Each image begins with send_image command followed by the sequence of binary packets with image thumbnail data and full image data.
Starts sending a new image to the channel. The successful response includes image_id
which must be used in all data packets for this image.
Name | Type | Value / Description |
---|---|---|
command |
string | send_image |
seq |
integer | Command sequence number |
channel |
string | The channel to send the message to |
type |
string | Image type. Only jpeg is currently supported |
thumbnail_content_length |
integer | Image thumbnail content length in bytes |
content_length |
integer | Full image content length in bytes |
width |
integer | Full image width in pixels |
height |
integer | Full image width in pixels |
source |
string | Image source (camera or library ) |
for |
string | Optional username to send image to. Other users in the channel won't be receiving this image |
{
"command": "send_image",
"seq": 2,
"channel": "Reichenbach Falls",
"type": "jpeg",
"source": "camera",
"width": 1279,
"height": 959,
"thumbnail_content_length": 10616,
"content_length": 183716
}
{
"seq": 2,
"success": true,
"image_id": 22695
}
{type(8) = 0x02, image_id(32), image_type(32) = 0x02, data[]}
{type(8) = 0x02, image_id(32), image_type(32) = 0x01, data[]}
After successfully connecting to the channel and receiving channel status you can start sending text messages.
Sends a new text message to the channel.
Name | Type | Value / Description |
---|---|---|
command |
string | send_text_message |
seq |
integer | Command sequence number |
channel |
string | The channel to send the message to |
text |
string | Message text. 30 Kb maximum |
for |
string | Optional username to send text message to. Other users in the channel won't be receiving this text message |
{
"command": "send_text_message",
"seq": 3,
"channel": "Reichenbach Falls",
"text": "Where are you?",
"for": "holmes"
}
{
"seq": 3,
"success": true
}
After successfully connecting to the channel and receiving channel status you can start sending locations.
Sends user's location to the channel.
Name | Type | Value / Description |
---|---|---|
command |
string | send_location |
seq |
integer | Command sequence number |
channel |
string | The channel to send the message to |
latitude |
number | Shared location latitude |
longitude |
number | Shared location longitude |
accuracy |
number | Shared location accuracy in meters |
formatted_address |
string | Shared location reverse geocoding result (street address) |
for |
string | Optional username to send location to. Other users in the channel won't be receiving this location data |
{
"command": "send_location",
"seq": 3,
"channel": "Reichenbach Falls",
"latitude": 46.714475,
"longitude": 8.1806319,
"accuracy": 10,
"formatted_address": "Hausenstrasse 34, 3860 Meiringen, Switzerland",
"for": "watson"
}
{
"seq": 3,
"success": true
}
Indicates there was a change in channel status, which may include channel being connected/disconnected, number of online users changed, or supported features changed.
Name | Type | Value / Description |
---|---|---|
command |
string | on_channel_status |
channel |
string | The name of the channel |
status |
string | Channel status. Can be online or offline |
users_online |
integer | Number of users currently connected to the channel. |
images_supported |
boolean | Channel will accept image messages. |
texting_supported |
boolean | Channel will accept text messages. |
locations_supported |
boolean | Channel will accept locations. |
error |
string | Includes error description, when channel disconnected due to error. |
error_type |
string | unknown , configuration Indicates error type. When set to configuration indicates that current channel configuration doesn't allow connecting using the channel API credentials used. |
{
"command": "on_channel_status",
"channel": "test",
"status": "online",
"users_online": 2,
"images_supported": true,
"texting_supported": true,
"locations_supported": true
}
Indicates the start of the new incoming stream. This event corresponds to start_stream
command sent by another channel user.
Name | Type | Value / Description |
---|---|---|
command |
string | on_stream_start |
type |
string | Stream type. Only audio is currently supported |
codec |
string | The name of audio codec used. Required for audio streams. Must be opus |
codec_header |
string | base64-encoded codec header buffer. Required for opus streams |
packet_duration |
integer | Audio packet duration in milliseconds. Values between 2.5 ms and 60 ms are supported |
stream_id |
integer | The id of the stream that started |
channel |
string | The name of the channel |
from |
string | The username of the sender of the message |
for |
string | The username of the recipient of the message if it was sent with for parameter |
{
"command": "on_stream_start",
"type": "audio",
"codec": "opus",
"codec_header": "gD4BPA==",
"packet_duration": 20,
"stream_id": 22695,
"channel": "test",
"from": "alex",
"for": "jim"
}
Indicates the stop of the incoming stream. This event corresponds to stop_stream
command sent by another channel user.
Name | Type | Value / Description |
---|---|---|
command |
string | on_stream_stop |
stream_id |
integer | The id of the stream that stopped |
{
"command": "on_stream_stop",
"stream_id": 22695
}
Indicates a server error.
Name | Type | Value / Description |
---|---|---|
command |
string | on_error |
error |
string | One of the error codes |
{
"command": "on_error",
"error": "server closed connection"
}
Indicates incoming image from the channel. This event corresponds to send_image
command sent by another channel user.
Name | Type | Value / Description |
---|---|---|
command |
string | on_image |
channel |
string | The name of the channel |
from |
string | The username of the sender of the image |
for |
string | The username of the recipient of the image if it was sent with for parameter |
message_id |
integer | The id of the image message |
type |
string | image content type (jpeg ) |
height |
integer | Image height (some clients don't provide this value) |
width |
integer | Image width (some clients don't provide this value) |
source |
string | Image source (camera or library ) |
{
"command": "on_image",
"channel": "test",
"from":"alex",
"for": false,
"message_id": 59725,
"source": "camera",
"width": 591,
"height": 1280,
"ct": "jpeg"
}
on_image
event is followed by the sequence of two binary packets with image thumbnail data and full image data.
Fields are stored in network byte order similar to audio stream packets.
{type(8) = 0x02, message_id(32), image_type(32) = 0x02, data[]}
{type(8) = 0x02, message_id(32), image_type(32) = 0x01, data[]}
Indicates incoming text message from the channel.
Name | Type | Value / Description |
---|---|---|
command |
string | on_text_message |
channel |
string | The name of the channel |
from |
string | The username of the sender of the text message |
for |
string|boolean | The username of the recipient of the text message if it was sent with for parameter, false otherwise |
message_id |
integer | The id of the text message |
text |
string | Message text |
{
"command": "on_text_message",
"channel": "test",
"from": "alex",
"for": false,
"message_id": 16777216,
"text": "Hello Zello!"
}
Indicates incoming shared location from the channel.
Name | Type | Value / Description |
---|---|---|
command |
string | on_location |
channel |
string | The name of the channel |
from |
string | The username of the sender of the shared location |
for |
string | The username of the recipient of the location if it was sent with for parameter |
message_id |
integer | The id of the shared location message |
latitude |
number | Shared location latitude |
longitude |
number | Shared location longitude |
formatted_address |
string | Shared location reverse geocoding result (street address) |
accuracy |
number | Shared location accuracy in meters |
{
"command": "on_location",
"channel": "test",
"from": "alex",
"message_id": 16777217,
"latitude": 30.27386375722625,
"longitude": -97.76014980128478,
"rgl": "1317 W 6th St, Austin"
}
Error Code | Description |
---|---|
unknown command | Server didn't recognize the command received from the client. |
internal server error | An internal error occured within the server. If the error persists please contact us at [email protected] |
invalid json | The command received included malformed JSON |
invalid request | The server couldn't recognize command format. |
not authorized | Username, password or token are not valid. |
not logged in | Server received a command before successful logon . |
not enough params | The command doesn't include some of the required attributes. |
server closed connection | The connection to Zello network was closed. You can try re-connecting. |
channel is not ready | Channel you are trying to talk to is not yet connected. Wait for channel online status before sending a message |
listen only connection | The client tried to send a message over listen-only connection. |
failed to start stream | Unable to start the stream for unknown reason. You can try again later. |
failed to stop stream | Unable to stop the stream for unknown reason. This error is safe to ignore. |
failed to send data | An error occured while trying to send stream data packet. |
invalid audio packet | Malformed audio packet is received. |
Feature | Consumer Zello | Zello Work |
---|---|---|
Access channels using authorized user credentials | Supported | Supported |
Access channels anonymously in listen only mode | Supported | Not supported |
Send and receive voice messages | Supported | Supported |
Interoperability with Zello apps on Android, iOS, and PC | Supported | Supported |
Create and access ad hoc channels anonymously | Planned | Planned |
Send and receive images | Supported | Supported |
Send and receive text messages | Supported | Supported |
Send and receive locations | Supported | Supported |
Send and receive emergency alerts | - | Planned |