Skip to content

Latest commit

 

History

History
1445 lines (1078 loc) · 47.4 KB

doc.md

File metadata and controls

1445 lines (1078 loc) · 47.4 KB

Decent Messaging API Documentation

Version Released
Not yet

This document acts as a user guide to the public APIs of Decent servers as defined by the specification. If you are writing a server implementation, please refer to that document also.

Table of contents

Transport

Servers support the following two forms of transport, which are meant to be used in conjunction with eachother:

HTTP(S) endpoints - For client->server requests

The HTTP API is accessed via /api/. All endpoints respond in JSON, and those which take request bodies expect it to also be formatted using JSON. Server implementors may choose an appropriate HTTP status code for responses, however this must not be relied on by clients.

WebSocket events - For server->client event notifications

Messages sent to and from sockets are JSON strings, following the format { evt, data }, where evt is a name representing the meaning of the event, and data is an optional property specifying any additional data related to the event.


Authentication

Clients should authenticate using both of the following methods at the same time.

With HTTP(S) - per-request

When a request is made to an API endpoint, the server searches for a session ID string given in the request using one of:

  • ?sessionID in query string (URL)
  • sessionID in request body
  • X-Session-ID header (recommended)

Note that if session IDs are provided more than once in a single request the request will error with REPEATED_PARAMETERS.

If a session ID is provided but invalid/expired, the request is immediately terminated with an INVALID_SESSION_ID error.

If the request requires permission(s) and a session ID is not provided or its user does not posses the expected permissions, the request is terminated with a NOT_ALLOWED error.

Note that "you" in this document typically refers to the provided session ID's related user.

With WebSockets - ping/pong periodically

'pingdata' event

Sent periodically (typically every 10 seconds) by the server, as well as immediately upon the client socket connecting. Clients should respond with a pongdata event, as described below. No data is sent with the event.

'pongdata' event

Should be sent from clients (unlike all other WebSocket transmissions) in response to pingdata. Notifies the server of any information related to the particular socket. Passed data should include:

  • sessionID, if the client is "logged in" or keeping track of a session ID. This is used for keeping track of which users are online.
    • Note null means 'not logged in'.

Errors

Nearly all HTTP endpoints return errors situationally. Generally, when the processing of a request errors, its response will have the error property, which will follow the form { code, message }. Server implementors may optionally include extra infomation in this return map, using any key other than code or message.

The message property is a string of a human-readable English message briefly explaining what went wrong, and the code is a permanent identifier string for the type of error that happened. Checking code is useful for displaying custom messages or behavior when particular errors occur.

Error codes
Error code Meaning
NOT_FOUND The requested thing was not found
NOT_YOURS Your attempt to do something impactful was rejected because you are not the owner/author of the thing
MISSING_PERMISSION You do not have a required permission
NO The server does not support or does not want to fulfill your request
ALREADY_PERFORMED That action has already been performed
FAILED Something went wrong internally
INCOMPLETE_PARAMETERS A property is missing from the request's parameters
REPEATED_PARAMETERS A parameter is specified twice in the request
INVALID_PARAMETER_TYPE A parameter is the wrong type
INVALID_SESSION_ID There is no session with the provided session ID
INVALID_NAME Provided name is invalid
NAME_ALREADY_TAKEN The passed name is already used by something else
SHORT_PASSWORD Password is too short
INCORRECT_PASSWORD Incorrect password

Permissions

Permissions in Decent are a way to limit and grant certain abilities to users.

How permissions work

Permissions are stored within a map of keys (representing individual permissions) to boolean values (or undefined). For example, the following permissions object describes being able to read but not send messages:

{
  "readMessages": true,
  "sendMessages": false
}

Individual permissions are passed according to a cascade of roles. If two or more permission objects are applied (typically based on the roles a user has), then individual permissions are determined by the most prioritized roles. For example, consider these three permission objects:

{
  "sendMessages": false
}

{
  "readMessages": true,
  "sendMessages": true
}

{
  "readMessages": false,
  "sendMessages": false
}

Suppose we consider the first, top-most object to have the greatest priority, and that the second and third each in turn have less priority.

If all three permission objects are applied to a user, then to calculate the user's permissions, we start by looking at the most prioritized object. This object contains one property, sendMessages: false. From this, we know that the user is not permitted to send messages; this is absolutely true, regardless of any other permission objects, since this object is the most prioritized one.

Then we move to the next permission object: {readMessages: true, sendMessages: true}. The readMessages: true permission tells us that the user is allowed to read messages. There is also a sendMessages property, but we ignore this, since we have already determined that the user is not permitted to send messages.

We look at the final permission object: {readMessages: false, sendMessages: false}. There are two properties here, but these have both already been determined earlier, so we ignore them. Since we have gone through all permission objects applied to the user, we come to the conclusion that the user may read but not send messages.

The actual priority of permission objects is determined according to the roles applied to the user and channel-specific permissions (which are dependent on the roles), and the order is determined as follows:

Permissions for roles of the user (both globally and channel-specific) are prioritized according to the role prioritization order. Note that the order of the user's roles property does not have any effect on the order roles that are applied when calculating their perissions.

Permission table

A set of permissions can be configured for different roles. When these roles are attached to users, they grant or revoke specific privileges within the entire server.

Below is a table of all permissions.

Name Description
manageServer Allows changes to server settings.
manageUsers Allows for updating of users other than yourself, and allows deletion of users.
manageRoles Allows creation/deletion/modification of roles under you.
grantRoles Allows granting/revoking roles under you to users.
manageChannels Allows management and editing of channels and their permissions.
managePins Allows for pinning and unpinning of messages.
manageEmotes Allows for creation and removal of emotes.
readMessages Allows for viewing of channel messages; if false, the channel does not show up in the channel list.
sendMessages Allows for sending messages.
deleteMessages Allows for deleting messages that you did not author.
sendSystemMessages Allows for sending system messages.
uploadImages Allows image uploads.
allowNonUnique Allows the creation of things with non-unique names.

Channel-specific permissions

Only the following permissions are applicable as channel-specific permission overrides:

Name Change in meaning
manageChannels Allows changes to the role permission overrides of this channel
readMessages If false, the channel will not appear in the channel list for you
sendMessages
deleteMessages
sendSystemMessages

Miscellaneous

Endpoints

Retrieve server implementation details [GET /api]

Returns { decentVersion, implementation, useSecureProtocol }, where decentVersion is a string version number corresponding to the specification version the server supports/providers, implementation is a string typically refering to the name of the server impementation, and the boolean useSecureProtocol should be true when this server is only accessible via the HTTPS and WSS protocols.

Should be used to check to see if a particular server is compatible with the version of the spec that you (the client) support. Note that Decent follows SemVer, so unless the MAJOR (first) portion of the version number is different to what you expect communication should work fine.

GET /api/

<- {
<-   "implementation": "@decent/server",
<-   "decentVersion": "1.0.0",
<-   "useSecureProtocol": true
<- }

Upload an image [POST /api/upload-image]

  • requires permission: uploadImages
  • expects form data (multipart/form-data)
    • image (gif/jpeg/png) - The image to upload. Max size: 10MB

Returns { path }, where path is a relative URL to the uploaded image file.

POST /api/upload-image

-> (form data)

<- {
<-   "path": "/uploads/1234/image.png"
<- }

This endpoint may return an error, namely FAILED, NO, or NOT_ALLOWED.


Settings

{
  "name": string,
  "iconURL": string,
}

Events

server-settings/update

Emitted with data { settings } when the server settings are modified.

Endpoints

Retrieve all settings [GET /api/settings]

Returns { settings }, where settings is an object representing server-specific settings.

GET /api/settings

<- {
<-   "settings": {
<-     "name": "Unnamed Decent chat server",
<-     "iconURL": "https://meta.decent.chat/uploads/..."
<-   }
<- }

Modify settings [PATCH /api/settings]

  • requires permission: manageServer
  • name (string; optional)
  • iconURL (string; optional)

Returns {} if successful. Updates settings with new values provided, and emits server-settings/update.

PATCH /api/settings

-> {
->   "name": "My Server"
-> }

<- {}

Emotes

{
  "shortcode": string, // Unique string without colons or spaces
  "imageURL": string
}

Events

emote/new

Sent to all clients when an emote is created. Passed data is in the format { emote }.

emote/delete

Sent to all clients when an emote is deleted. Passed data is in the format { shortcode }.

Endpoints

List emotes [GET /api/emotes]

Returns { emotes }, where emotes is an array of emote objects.

GET /api/emotes

<- {
<-   "emotes": []
<- }

Add a new emote [POST /api/emotes]

  • requires permission: manageEmotes
  • imageURL (string)
  • shortcode (string) - Should not include colons (:) or spaces. Must be unique, even if the user has the allowNonUnique permission.

Returns {} if successful. Emits emote/new.

POST /api/emotes

-> {
->   "imageURL": "https://example.com/path/to/emote.png",
->   "shortcode": "package"
-> }

<- {}

View an emote [GET /api/emotes/:shortcode]

  • in-url shortcode (string)

302 redirects to the imageURL of the emote specified. 404s if not found or invalid.

<!-- To view the :package: emoji in HTML: -->
<img src='/api/emotes/package' width='16' height='16'/>

Delete an existing emote [DELETE /api/emotes/:shortcode]

  • requires permission: manageEmotes
  • in-url shortcode (string)

Returns {} if successful. Emits emote/delete.

DELETE /api/emotes/package

<- {}

Sessions

{
  "id": string,
  "dateCreated": float // Unix time at creation. May be more accurate using decimal places
}

Endpoints

Fetch the current user's sessions [GET /api/sessions]

  • requires a valid session ID & user

Responds with { sessions }, where sessions is an array of sessions that also represent the user that the provided session represents (the callee; you).

GET /api/sessions

<- {
<-   "sessions": [
<-     {
<-       "id": "12345678-ABCDEFGH",
<-       "dateCreated": 123456789000
<-     }
<-   ]
<- }

Login [POST /api/sessions]

  • username (string)
  • password (string)

Responds with { sessionID } if successful, where sessionID is the ID of the newly-created session. Related endpoint: register.

POST /api/sessions

-> {
->   "username": "admin",
->   "password": "abcdef"
-> }

<- {
<-   "sessionID": "12345678-ABCDEFGH"
<- }

Fetch session details [GET /api/sessions/:id]

  • does not require a session ID via means other than in the URL
  • in-url id (string, session ID)

Responds with { session, user } upon success, where session is a session and user is the user this session represents.

GET /api/sessions/12345678-ABCDEFGH

<- {
<-   "session": {
<-     "id": "12345678-ABCDEFGH",
<-     "dateCreated": 123456789000
<-   },
<-   "user": {
<-     "id": "1234",
<-     "username": "admin",
<-     // ...
<-   }
<- }

Logout [DELETE /api/sessions/:id]

  • does not require a session ID via means other than in the URL
  • in-url id (string, session ID)

Responds with {} upon success. Any further requests using the provided session ID will fail.

DELETE /api/sessions/12345678-ABCDEFGH

<- {}

Messages

{
  "id": ID,
  "channelID": ID,

  // The message type. See below
  "type": string,

  // The content of the message
  "text": string,

  // The author's details, at the time of creation;
  // if message.type = "system" these will all be null.
  "authorID": ID,
  "authorUsername": Name,
  "authorAvatarURL": string,

  // Dates are returned as the number of seconds since UTC 1970-1-1, commonly
  // known as Unix time. May be more accurate using decimal places.
  "dateCreated": float,
  "dateEdited": float | null,

  "pinned": boolean,
  "mentionedUserIDs": [ ID ]
}

Message types

There are currently two message types, "user" and "system". Messages sent by users are always marked "user", however both the server and users with the sendSystemMessage permission can choose to send system-level messages for things, such as user joins or when pins are added. Ideally, these would be styled differently in clients.

System messages lack author fields.

Mentions

Mentions target a single user only and are formatted as <@userID>, where userID is the ID of the user who is being mentioned. Mentions are stored per-user on the server. mentionedUserIDs is derived from the content of the message.

Events

message/new

Sent to all clients whenever a message is sent to any channel in the server. Passed data is in the format { message }, where message is a message representing the new message.

message/edit

Sent to all clients when any message is edited. Passed data is in the format { message }, where message is a message representing the new message.

message/delete

Sent to all clients when any message is deleted. Passed data is in the format { messageID }.

Endpoints

Send a message [POST /api/messages]

  • requires permissions:
    • sendMessages
    • sendSystemMessages, if type == "system"
  • channelID (ID) - The parent channel of the new message
  • text (string) - The content of the message
  • type (string; defaults to "user")

On success, emits message/new and returns { messageID }. Also marks channelID as read for the author. Emits user/mentions/add to mentioned users, if any.

POST /api/messages

-> {
->   "channelID": "5678",
->   "text": "Hello, world!"
-> }

<- {
<-   "messageID": "1234"
<- }

Retrieve a message [GET /api/messages/:id]

  • requires permission: readMessages
  • in-url id (ID) - The ID of the message to retrieve

Returns { message } where message is a message object.

GET /api/messages/1234

<- {
<-   "message": {
<-     "id": "1234",
<-     // ...
<-   }
<- }

Edit a message [PATCH /api/messages/:id]

  • requires a session ID where the session user is the author of message id
  • in-url id (ID) - The ID of the message to edit
  • text (string) - The new content of the message

Emits message/edit and returns {}.

PATCH /api/messages/1234

-> {
->   "text": "Updated message text"
-> }

<- {}

This endpoint will return a NOT_YOURS error if you do not own the message in question. Emits user/mentions/add to newly mentioned users and user/mentions/remove to users who are no longer mentioned, if any.

Delete a message [DELETE /api/messages/:id]

  • requires one of:
    • session with ownership of message id
    • permission (for channel of specified message) deleteMessages
  • in-url id (ID) - The ID of the message to delete

Emits message/delete and returns {}.

DELETE /api/messages/1234

<- {}

This endpoint may return a NOT_YOURS error if you do not own the message in question. Note that admins may delete any message. Emits user/mentions/remove to all previously-mentioned users.


Channels

{
  "id": ID,
  "name": string // Does not include a hash
}

Extra data

This data is only present if a valid, logged-in session ID is provided to channel-returning endpoints.

{
  // Number of 'unread' messages, capped at 200. Unread messages are
  // simply messages that were sent more recently than the last time
  // the channel was marked read by this user.
  "unreadMessageCount": number,

  "oldestUnreadMessageID": ID | null,
}

Events

channel/new

Sent to all clients when a channel is created. Passed data is in the format { channel }, where channel is a channel representing the new channel.

channel/update

Sent to all clients when a channel is updated (renamed, marked as read, etc). Passed data is in the format { channel }, including channel.unreadMessageCount if the socket is actively ponging sessionIDs.

channel/pins/add

Sent to all clients when a message is pinned to a channel. Passed data is in the format { message }, where message is the message that was pinned.

channel/pins/remove

Sent to all clients when a message is unpinned from a channel. Passed data is in the format { messageID }, where messageID is the ID of the message that was unpinned.

channel/delete

Sent to all clients when a channel is deleted. Passed data is in the format { channelID }.

Endpoints

Get list of channels [GET /api/channels]

  • does not require session, however:
    • channels where the session user does not have the readMessages permission will not be returned
    • returns extra data with session

Returns { channels }, where channels is an array of channels. Note unreadMessageCount will only be returned if this endpoint receives a session.

GET /api/channels

<- {
<-   "channels": [
<-     {
<-       "id": "5678",
<-       "name": "general"
<-     }
<-   ]
<- }

Create a channel [POST /api/channels]

  • requires permission manageChannels
  • name (name) - The name of the channel.

On success, emits channel/new and returns { channelID }.

POST /api/channels

-> {
->   "name": "general"
-> }

<- {
<-   "channelID": "5678"
<- }

Retrieve a channel [GET /api/channels/:id]

  • does not require session, however:
  • in-url id (ID) - The ID of the channel.

Returns { channel }. Note extra data will only be returned if this endpoint receives a logged-in session ID.

GET /api/channels/5678

<- {
<-   "channel": {
<-     "id": "5678",
<-     "name": "general"
<-   }
<- }

Rename a channel [PATCH /api/channels/:id]

  • requires permission manageChannels
  • in-url id (ID) - The ID of the channel.
  • name (name) - The new name of the channel

Returns {} if successful, emitting channel/update.

PATCH /api/channels/5678

-> {
->   "name": "best-channel"
-> }

<- {}

Delete a channel [DELETE /api/channels/:id]

  • requires permission manageChannels
  • in-url id (ID) - The ID of the channel to delete.

Returns {} if successful. Emits channel/delete.

DELETE /api/channels/5678

<- {}

Mark a channel as read [POST /api/channels/:id/mark-read]

  • requires permission (for specified channel) readMessages
  • in-url id (ID) - The ID of the channel.

Marks the channel as read (ie. sets unreadMessageCount to 0), returning {}. Emits channel/update including extra data if this socket is authenticated.

POST /api/channels/5678/mark-read

<- {}

Get messages in channel [GET /api/channels/:id/messages]

  • requires permission (for specified channel) readMessages
  • in-url id (ID) - The ID of the channel to fetch messages of.
  • before (ID; optional) - The ID of the message right after the range of messages you want.
  • after (ID; optional) - The ID of the message right before the range of messages you want.
  • limit (integer; optional, default 50) - The maximum number of messages to fetch. Must be 1 <= limit <= 50.

Returns { messages }, where messages is an array of the most recent messages sent to this channel. If limit is given, it'll only fetch that many messages.

If before is specified, it'll only return messages sent before that one; and it'll only return messages sent after after.

GET /api/channels/5678/messages

<- {
<-   "messages": [
<-     {
<-       "id": "1234",
<-       "channelID": "5678",
<-       // ...
<-     },
<-     {
<-       "id": "1235",
<-       "channelID": "5678",
<-       // ...
<-     }
<-   ]
<- }
GET /api/channels/5678/messages?after=1234

<- {
<-   "messages": [
<-     {
<-       "id": "1235",
<-       "channelID": "5678",
<-       // ...
<-     }
<-   ]
<- }

Update channel-specific role permissions [PATCH /api/channels/:id/role-permissions]

  • requires permission (for specified channel) manageChannels
  • in-url id (ID)
  • rolePermissions - an object map of role IDs to their permissions, limited by channel-specific applicable permissions only
    • The internal role _everyone cannot override permissions other than readMessages, as you must be logged in to perform any other action.

Returns {} if successful. Note that if a role is not specified on the roles parameter, its permissions on the channel will not be changed. To delete an entry, pass {} as the role's permissions; since this would reset the role's permissions all to unset, the role would have no effect, and is removed from the channel's rolePermissions map.

PATCH /api/channels/1234/role-permissions

-> {
->   "rolePermissions": {
->     "_everyone": {
->       "readMessages": false,
->       "sendMessages": false
->     },
->     "123": {
->       "readMessages": true,
->       "sendMessages": true
->     }
->   }
-> }

<- {}

Get channel-specific role permissions [GET /api/channels/:id/role-permissions]

  • in-url id (ID)

Returns { rolePermissions } if successful, where rolePermissions is a map of role IDs to their individual permissions.

GET /api/channels/1234/role-permissions

<- {
<-   "rolePermissions": {
<-     "_everyone": {
<-       "readMessages": false,
<-       "sendMessages": false
<-     },
<-     ...
<-   }
<- }

Retrieve all pinned messages [GET /api/channels/:id/pins]

  • requires permission (for specified channel) readMessages
  • in-url id (ID)

Returns { pins }, where pins is an array of messages that have been pinned to this channel.

GET /api/channels/5678/pins

<- {
<-   "pins": [
<-     {
<-       "id": "1235",
<-       "channelID": "5678",
<-       // ...
<-     }
<-   ]
<- }

Pin a message [POST /api/channels/:id/pins]

  • requires permission (for specified channel) managePins
  • in-url id (ID)
  • messageID (ID) - The message to pin to this channel.

Returns {} if successful. Emits channel/pins/add.

POST /api/channels/5678/pins

-> {
->   "messageID": "1234"
-> }

<- {}

Unpin a message [DELETE /api/channels/:channelID/pins/:messageID]

  • requires permission (for specified channel) managePins
  • in-url channelID (ID)
  • in-url messageID (ID) - The ID of the message to unpin. Errors if not pinned.

Returns {} if successful. Emits channel/pins/remove.

DELETE /api/channels/5678/pins/1234

<- {}

Users

{
  "id": ID,
  "username": Name,

  "avatarURL": string,
  "flair": string | null,

  "online": boolean,
  "roleIDs": array, // Array of string IDs for each role the user has, not including "_user" or "_everyone",

  "email": string | null // Only provided if the requested user is the same as the sessionID provides
}

Events

user/new

Sent to all clients when a user is created. Passed data is in the format { user }.

user/delete

Sent to all clients when a user is deleted. Passed data is in the format { userID }.

user/online

Sent to all clients when a user becomes online. This is whenever a socket tells the server that its session ID is that of a user who was not already online before. Passed data is in the format { userID }.

user/offline

Sent to all clients when a user becomes offline. This is whenever the last socket of a user who is online terminates. Passed data is in the format { userID }.

user/update

Sent to all clients when a user is mutated using PATCH /api/users/:userID. Passed data is in the format { user }.

user/mentions/add

When a user is mentioned, this is sent to all sockets authenticated as them. Passed data is in the format { message }, where message is the new / just edited mesage that mentioned the user.

user/mentions/remove

When a message is deleted or edited to remove the mention of a user, all sockets authenticated as the unmentioned user are sent this event. Passed data is in the format { messageID }, where messageID is the ID of the message that just stopped mentioning the user.

Endpoints

Fetch users [GET /api/users]

Returns { users }, where users is an array of users.

GET /api/users

<- {
<-   "users": [
<-     {
<-       "id": "1234",
<-       "username": "test-user",
<-       // ...
<-     }
<-   ]
<- }
GET /api/users?sessionID=adminsid123

<- {
<-   "users": [
<-     {
<-       "id": "1234",
<-       "username": "test-user",
<-       // ...
<-     }
<-   ]
<- }

Register (create new user) [POST /api/users]

  • username (name) - Must be unique
  • password (string) - Errors if shorter than 6 characters

Responds with { user } if successful, where user is the new user object. Emits user/new. Log in with POST /api/sessions.

POST /api/users

-> {
->   "username": "joe",
->   "password": "secret"
-> }

<- {
<-   "user": {
<-     "id": "8769",
<-     "username": "joe",
<-     // ...
<-   }
<- }

Retrieve a user by ID [GET /api/users/:id]

  • does not require a valid session, howerver:
    • returns extra data (email) if the provided session represents the user requested
  • in-url id (ID) - The user ID to fetch

Returns { user }.

GET /api/users/1

<- {
<-   "user": {
<-     "id": "1",
<-     "username": "admin",
<-     // ...
<-   }
<- }

List mentions of a user [GET /api/users/:id/mentions]

  • does not require session, however:
    • only returns messages where you have the viewMessages permission for the message's channel
  • in-url id (ID) - The user ID to fetch the mentions of
  • limit (int <= 50; default 50) - The maximum number of mentions to fetch.
  • skip (int; default 0) - Skips the first n mentions before returning

Returns { mentions }, where mentions is an array of messages. Note that mentions are sorted by creation date: mentions[0] is the most recent mention.

Combining limit and skip can net you simple pagination.

GET /api/users/1/mentions?limit=1

<- {
<-   "mentions": [
<-     {
<-       "text": "Hey <@1>! How are you?"
<-       // ...
<-     },
<-
<-     // ...
<-   ]
<- }

Update user details [PATCH /api/users/:id]

  • requires valid, logged-in session (see below)
  • in-url id (ID) - The user ID to patch

The following parameters are available to sessions that represent the user being updated:

  • password (object; optional):
    • new (string) - Errors if shorter than 6 characters
    • old (string) - Errors if it doesn't match user's existing password

The following parameters are available to sessions that represent the user being updated, or have the manageUsers permission:

  • email (string | null; optional) - Not public, used to generate avatar URL
  • flair (string | null; optional) - Displayed beside username in chat, errors if longer than 50 characters

Returns {} and applies changes, assuming a valid session for this user (or an admin) is provided and no errors occur. Also emits user/update.

PATCH /api/users/1

(with session representing user id 1)

-> {
->   "password": {
->     "old": "abcdef",
->     "new": "secure"
->   }
-> }

<- {}
PATCH /api/users/12

(with session representing an admin)

-> {
->   "roleIDs": [ "id-of-role", "id-of-role-2" ],
->   "flair": null
-> }

<- {}

('flair: null' removes the flair.)

Give a role to a user [POST /api/users/:userID/roles]

  • requires permission: grantRoles
    • also require more permissions (see below)
  • in-url userID (ID) - The ID of the user to give the role to
  • roleID (ID) - The ID of the role to be given

The role may only be given if the requesting user has all the permissions that are specified by that role (even if the value specified by the role is false).

On success, emits user/update and returns {}.

Take a role from a user [DELETE /api/users/:userID/roles/:roleID]

  • requires permission: grantRoles
    • also requires more permissions (see below)
  • in-url userID (ID) - The ID of the user to take the role from
  • in-url roleID (ID) - The ID of the role to be taken

As with giving a role, the role may only be taken if the requesting user has all the permissions that are specified by that role (even if the value specified by the role is false).

On success, emits user/update and returns {}.

Retrieve a list of a user's roles [GET /api/users/:id/roles]

  • does not require a session
  • in-url id (ID) - The ID of the user to fetch the roles of

Returns { roleIDs }. (Not actually more functionally useful than simply checking user.roleIDs from /api/users/:id; only exists for convenience.)

Retrieve a user by ID [GET /api/users/:id]

  • does not require a session, however:
    • if the provided session represents the user id, returns extra data (email)
  • in-url id (ID) - The user ID to fetch

Returns { user }.

GET /api/users/1

<- {
<-   "user": {
<-     "id": "1",
<-     "username": "admin",
<-     // ...
<-   }
<- }

Get a user's permissions [GET /api/users/:id/permissions]

  • in-url id (ID) - The user ID to fetch

Returns { permissions }, where permissions is a permissions object.

GET /api/users/1/permissions

<- {
<-   "permissions": {
<-     "manageServer": false,
<-     "manageUsers": false,
<-     "readMessages": true,
<-     // ...
<-   }
<- }

Get a user's channel-specific permissions [GET /api/users/:userID/channel-permissions/:channelID]

  • in-url userID (ID) - The user ID to fetch
  • in-url channelID (ID) - The channel ID to fetch

Returns { permissions }, where permissions is a permissions object containing permissions, with the given channel's role-specific permissions applied.

Delete a user [DELETE /api/users/:id]

  • requires permission: manageUsers
  • in-url id (ID) - The user to delete

Returns {} and emits user/delete.

Check if a username is available [GET /api/username-available/:username]

  • does not require session
  • in-url username (name)

On success, returns { available }, where available is a boolean for if the username is available or not. May return the error INVALID_NAME.

GET /api/username-available/patrick

<- {
<-   "available": false
<- }

Roles

{
  "id": ID,
  "name": string,
  "permissions": object, // A permissions object
}

See also

Events

role/new

Sent to all clients when a role is added. Passed data is in the format { role }.

role/update

Sent to all clients when a role is updated. Passed data is in the format { role }.

role/delete

Sent to all clients when a role is deleted. Passed data is in the format { roleID }.

Endpoints

List roles [GET /api/roles]

Returns { roles }, where roles is an array of role objects.

GET /api/roles

<- {
<-   "roles": [
<-     {
<-       "id": "_everyone",
<-       "name": "Everyone",
<-       "permissions": ...
<-     }
<-   ]
<- }

Retrieve role prioritization order [GET /api/roles/order]

Returns { roleIDs }, where roleIDs is an array of role IDs representing the order that roles are applied when permissions are calculated. Internal roles, such as _user and _everyone, are not included.

Change role prioritization order [PATCH /api/roles/order]

  • requires permission: manageRoles
  • roleIDs (array of IDs) - The order roles are applied in
    • Must contain all non-internal role IDs exactly once (no more, no less)
    • The requesting user can reorder all roles which are already prioritized below their own most-prioritized role; the order of said role and all roles above must not be changed
    • The order cannot be changed such that the requesting user would not have the manageRoles permission anymore

Returns {} when successful. Changes the order that roles are applied in; initial items are the most prioritized. See Permissions.

PATCH /api/roles/order

-> {
->   "roleIDs": [
->     "abc",
->     "123",
->     "999"
->   ]
-> }

// Then...
GET /api/roles

<- {
<-   "roles": [
<-     {"id": "abc", ...},
<-     {"id": "123", ...},
<-     {"id": "999", ...},
<-     {"id": "_user", ...},
<-     ...
<-   ]
<- }

Retrieve a role by ID [GET /api/roles/:id]

Returns { role }.

GET /api/roles/_everyone

<- {
<-   "role": {
<-     "id": "_everyone",
<-     "name": "Everyone",
<-     "permissions": ...
<-   }
<- }

Add a new role [POST /api/roles]

  • requires permission: manageRoles
  • name (string) - Max length 32.
  • permissions (Permissions object) - this role's intended permissions
    • Cannot contain permissions that the requesting session's user does not have

Returns { roleID } if successful, where roleID is the ID of the new role. Emits role/new. The role is added to the role prioritization order immediately under (less prioritized than) the creating user's most-prioritized role.

Update a role [PATCH /api/roles/:id]

  • requires permission: manageRoles
  • in-url id (ID)
  • name (string; optional) - Max length 32.
  • permissions (Permissions object) - the new intended permissions for this role
    • Cannot contain permissions that the requesting session's user does not have

Returns {} and emits role/update if successful. May emit user/update as required if users' computed permissions change.

Delete a role [DELETE /api/roles/:id]

Returns {} if successful. Emits role/delete. The role is removed from the role prioritization order.