Messaging Interface

Target release
Epic
Document status
Draft Specification
Document owner
ContactShailesh Kochhar, Pramod Verma




Overview

Different kinds of collaboration possible

  • Real-time, syncronous
  • Threaded conversations, asyncronous
  • Q&A, asyncronous

This doc covers the functional interface which must be implemented by messaging services to allow its real-time synchronous collaboration capability to be exposed within Sunbird.

The functional interface will provide an implementation of the Sunbird abstractions which enable sending and receiving of messages.

Architecture

Sunbird provides plugin points for installing

  1. a messaging interface for clients
  2. a messaging service adapter which can connect with a messaging service backend.

The Sunbird client (web/mobile) will install a client plugin allowing it to connect to the messaging backend via the messaging interface exposed by the Sunbird server. 

Architecture for Messaging Service Integration

Entities

The messaging interface provides an abstraction over messaging services to enable one-or-more messaging providers to plug-in to Sunbird. The interface provides the means to manipulate and manage:


  • Participants: each participant in a group messaging session is associated with an account. Consider three types of accounts: user, guest and bot
  • Identity: each user account will be associated with a Sunbird identity, it can also be associated with other third-party identities
  • Rooms: equivalent of a group chat. Multiple accounts can participate in a room
  • Sessions: are associated with devices which the participant uses. Multiple sessions may be initiated from a single device
  • Events: are an abstraction over forms of content. A message is one event type.
  • Devices: provide a means for offline management of encryption keys. A device is not always a physical entity, a browser is also a device

Participant management

For a participant to send/receive messages, she/he/it must be registered with the messaging service. Registered participants must authenticate to interact with the service and perform operations.

Register: POST /msg/client/v1/register?medium=<medium>?type=<type>

Register a user account with profile details using the messaging backend chosen by the instance administrator.

  • This API may be used to register two types of user accounts (see Registering Bots for details on registering bot accounts)
    • A guest account which has limited access to messaging APIs. This may not be supported by all backends
    • A user account which does not have limitations
  • Once the registration is successful, the server must issue the client an authenticatedUserToken which must be used in subsequent API calls from this device
  • The server will attempt to generate an account with the provided username, however, if the username is not available, the server will return a corresponding error.
  • The selected username must conform to the constraints specified below, if it does not meet the constraints, the server will return a corresponding error.
Request
ParameterTypeDescription
Query Parameters
mediumString

The medium through which the user’s identity is to be validated. One of email or sms. Required

typeStringThe type of registration. One of guest or user
JSON Body Parameters
usernameString

The desired username for the user. The username must be a minimum of six characters and may use any of the following characters [0-9a-zA-Z_ - .]

If it is omitted, the server must generate a username for the account.

deviceIdStringID of the client device. This is used to register a device for the new account. If it is omitted, the server must generate a deviceId for this device.
firstNameStringThe first name of the new user.
lastNameStringThe last name of the new user.
addressString

The address being used to register the user which will be attached to this account. Required

If medium is email, this should be an email address. If medium is sms, this should be a phone number in international format

sessionIdIntThe ID of the validation session which sent a token to the address. Required (see validationCode API)
validationCodeStringA valid code received by the user. Required (see validationCode API)
Example
POST /msg/client/v1/register?medium=sms&type=user
Content-type: application/json
{
“username”: “chacha_chaudhary”,
“password”: “a_very_weak_password”,
“deviceId”: “f071ade8716bcc24”,
“firstName”: “Chacha”,
“lastName”: “Chaudhary”,
“address”: “+919999000111”,
“sessionId”: 4176451,
“validationCode”: “SB-418912”,
}
Response: Status 200

Indicates that a new account has been created for the user

{
“username”: “chacha_chaudhary”,
“userAddress”: “chacha_chaudhary@org.sunbird.msg.slack”,
“deviceId”: “f071ade8716bcc24”,
“authenticatedUserToken”: “brainworksfasterthanacomputer”
}
Response: Status 400

Indicates that there was an error in the request which made it invalid. This may be one of the following error codes

  • ERR_USERNAME_UNAVAILABLE: The username provided is already being used
  • ERR_USERNAME_INVALID: The username provided is not a valid username
  • ERR_ADDRESS_INVALID: The address provided is not in a valid format for the medium
  • ERR_CODE_INVALID: The validationCode provided is not valid for the address
  • ERR_CODE_EXPIRED: The validationCode provided has expired
{
“errcode”: “ERR_USERNAME_INVALID”,
“error”: “Username is not allowed to contain the ‘?’ character”
}
Response: Status 429

The request was rate-limited because of too many requests

Register Bot: POST /msg/client/v1/registerBot

Request Code: POST /msg/client/v1/identity/code/request?medium=<medium>

Request that a code be sent to the user to validate their ownership of a identity address using either email or sms medium

Request

Parameter

Type

Description

URL Parameters

medium

String

The medium through which to send the validation token, can either be email or sms

JSON Body Parameters

clientSecret

String

Unique client secret used to identify the attempt to validate the user’s address. The secret can use the following characters [0-9a-zA-Z.=_-] Required

address

String

The address where to send the validation code. Required

If the medium is email, this should be an email address

If the medium is sms, this should be a phone number in international format (including country code)

attemptNumber

Integer

The count of the attempt being made to send the validation code, multiple requests with the same attemptNumber may be ignored. Required

Example
POST /msg/client/v1/identity/code/request?medium=sms
Content-type: application/json
{
“clientSecret”: “this_is_a_very_poor_client_secret”,
“address”: “+919999000111”,
“attemptNumber”: 1
}
Response: Status 200

Indicates that a validation code has been sent, the sessionId will be required when confirming the code

{
“sessionId”: 4176451
}
Response: Status 400

Indicates that there was an error in the request which made it invalid. This may be one of the following error codes

  • ERR_ADDRESS_INVALID: The address provided is not in a valid format
  • ERR_TOO_MANY_ATTEMPTS: The number of attempts has exceeded the maximum allowed by the service. May vary based on the service backend.

{
“errcode”: “ERR_ADDRESS_INVALID”,
“error”: “The address provided is not a valid email”
}

Validate Identity: POST /msg/client/v1/identity/code/validate?medium=<medium>

Validate that a messaging user is the owner of an identity address. This method could be called multiple times for a given username with different mediums. It is up to the service to provide the capability to have multiple identities for the same medium.

Request

Parameter

Type

Description

URL Parameters

medium

String

The medium through which to send the validation token, can either be email or sms

JSON Body Parameters

username

String

The username for the account to connect the identity with. The username is required if this call is made without an authenticatedUserToken in the header

address

String

The address being used to register the user which will be attached to this account. Required

If medium is email, this should be an email address.

If medium is sms, this should be a phone number in international format

sessionId

Int

The ID of the validation session which sent a token to the address. Required (see validationCode API)

validationCode

String

A valid code received by the user. Required (see validationCode API)

Example
POST /msg/client/v1/identity/code/validate?medium=sms
Content-type: application/json
{
“username”: “chacha_chaudhary”,
“address”: “+919999000111”,
“sessionId”: 4176451,
“validationCode”: “SB-418912”,
}
Response: Status 200

Indicates that the address has been linked to the username provided.

{
“status”: “OK”
}
Response: Status 400

Indicates that there was an error in the request which made it invalid. This may be one of the following error codes

  • ERR_ADDRESS_INVALID: The address provided is not in a valid format
  • ERR_CODE_INVALID: The validationCode provided is not valid for the address
  • ERR_CODE_EXPIRED: The validationCode provided has expired
{
“errcode”: “ERR_ADDRESS_INVALID”,
“error”: “The address provided is not a valid email”
}

Login: POST /msg/client/v1/login

Authenticates a user using an authentication method from:

  • Mobile number/OTP
  • OIDC identity
  • Username/one-time use token

The client first makes an empty login request which will return a 401 Unauthorised response and a sessionId in the response body. The client then uses this sessionId in subsequent requests to complete the login sequence.

Once the user has been authenticated, the server should issue the user an authenticatedUserToken which can be used for future authorization needs (eg: when making API calls).

Request

Parameter

Type

Description

JSON Body Parameters

sessionId

Int

The id of the login session initiated. A new sessionId can be generated by sending an empty request. Required

type

Enum

The type of authentication protocol to use.

Required

Can be one of org.sunbird.msg.login.otp, org.sunbird.msg.login.oidc, org.sunbird.msg.login.token

identity

IdentityObject

Identity information for the user who is logging in. Required

identity.medium

Enum

The medium of the identity which is being passed. Required

Can be one of org.sunbird.msg.id.email, org.sunbird.msg.id.phone, org.sunbird.msg.id.oidc

identity.address

String

The identity address of the user who is logging in. Required when identity.medium is org.sunbird.msg.id.email, org.sunbird.msg.id.phone

identity.uri

String

The identity URI for authenticating the user who is logging in. Required when identity.medium is org.sunbird.msg.id.oidc

token

String

The one-time use token to confirm the user’s identity. Required when type is org.sunbird.msg.login.otp or org.sunbird.msg.login.token

Login with OTP

To login using an OTP, the client sets the type parameter to org.sunbird.msg.login.otp, the identity.medium to org.sunbird.msg.id.phone and identity.address to the recipient’s phone number. The token is the OTP requested using the validate identity endpoint.

Login via token is analogous to login via OTP with the type and medium being set appropriately. The token can be received via any communication channel.

Example
POST /msg/client/v1/login
Content-type: application/json
{
“sessionId”: 9817263
“type”: “org.sunbird.msg.login.otp”,
“identity”: {
“medium”: “org.sunbird.msg.id.phone”,
“address”: “+919999000111”,
},
“token”: “SB-419817”,
}

Login with OIDC

To login using an OIDC Identity Provider (IdP), the client sets the type parameter to org.sunbird.msg.login.oidc, the identity.medium to org.sunbird.msg.id.oidc and identity.uri to the OIDC Authorization Request URI.

If the server allows logging in via the IdP selected, it redirects the client to visit the OIDC Authorization Request URI (via the appropriate HTTP response). The server should encode a callback endpoint into the Authorization Request URI.

The client presents the user with the OAuth2 consent page allowing access to the user’s identity information.

If the user authorises the request, the IdP will redirect the client to the redirect_uri along with an auth code. The redirect_uri should have been set to point to a server endpoint which acts as a confidential OIDC client. The server uses the auth code to request an access token from the IdP and retrieve the user’s identity information. This completes the OIDC login flow.

Once the OIDC login flow is completed on the server, the client makes a subsequent request to the login endpoint with the same sessionId and receives a success response.

  • Initiating the OIDC request
POST /msg/client/v1/login
Content-type: application/json
{
“sessionId”: 9817263
“type”: “org.sunbird.msg.login.oidc”,
“identity”: {
“medium”: “org.sunbird.msg.id.oidc”,
“uri”: “https://demo.open-sunbird.org/auth/realms/sunbird/protocol/openid-connect/auth?client_id=org.sunbird.msg&state=abc&scope=openid&response_type=code
},
}
  • Completing the OIDC request
POST /msg/client/v1/login
Content-type: application/json
{
“sessionId”: 9817263
“type”: “org.sunbird.msg.login.oidc”,
}
Response: Status 200

Indicates that the user has been authenticated

{
“username”: “chacha_chaudhary”,
“userId”: “chacha_chaudhary@org.sunbird.msg.slack”,
“deviceId”: “f071ade8716bcc24”,
“authenticatedUserToken”: “brainworksfasterthanacomputer”
}
Response: Status 401

Indicates that the request is missing authentication credentials

{
“errcode”: “ERR_USER_UNAUTHORIZED”,
“err”: “Not authorized to make this request”,
“sessionId”: 9817263
}
Response: Status 403

Indicates that the authentication has failed.

{
“errcode”: “ERR_USER_AUTHENTICATION_FAILED”,
“err”: “The credentials provided do not match a valid user”
}
Response: Status 400

Indicates that there was an error in the request which made it invalid

Logout: POST /msg/client/v1/logout

This logs out the user from the active session and makes the authenticatedUserToken unuseable for subsequent requests.

Request
Example
{}
Response: Status 200

Indicates that the user has been logged out of this device session

Room (Channel/Group) management

Create a room: POST /msg/client/v1/room/event/create

This endpoint creates a new room where subsequent events and messages can be dispatched. Room creation is itself an event which is the origin of subsequent events in the room. The room contains Sunbird metadata which can be used for discovery.

Rooms have two additional settings which control membership of the room. First is visibility which determines if the room is visible in public listings of the rooms available. The second is joinability which determines if the room can be joined without an invitation.

Request

Parameter

Type

Description

JSON Body Parameters

visibility

Enum

Controls the visibility of the room in room listing APIs. Must be one of unlisted or listed. If visibility is unlisted, then the room will not appear in room lists. If omitted, defaults to unlisted

membershipType

Enum

Controls the ability of users to join the room. Must be one of invite-only, token or open. If membershipType is invite-only, then new users must be added to the room. If membershipType is token, then a user must provide a token to join the room. If omitted, defaults to invite-only

name

String

The name to be given to the room. This will be displayed to other users and is recommended to be human-readable. Allowed characters are [0-9a-z_-/.] Required

topic

String

A topic for the room to help users understand what the room is intended for. May be omitted

contextUrl

String

A URL linking the room to a Sunbird context. Required

invite

List(InviteObject)

A list of messaging service usernames/userAddresses who will be invited to join the room

invite_external

List(InviteObject)

A list of invitees identified by external identifiers. (see the example below for the InviteObject)

version

Int

The version of the room object being created. Default to 1

Example
POST /msg/client/v1/room/event/create
Content-type: application/json
{
“visibility”: “listed”,
“membershipType”: “open”,
“name”: “chalis-chor”,
“topic”: “Chacha ke aadmi”,
“contextUrl”: “https://demo.sunbird.org/org/deade-f01945801-cee1”,
“invite”: [{
       “medium”: “org.sunbird.msg.id.userAddress”,
“address”: “chacha_chaudhary@org.sunbird.msg.slack”,
}],
“invite_external”: [{
“medium”: “org.sunbird.msg.id.email”,
“address”: “sabu@example.com”,
}],
“version”: 1
}
Response: Status 200

Indicates that the room was created successfully and returns the roomAddress.

{
“roomAddress”: “flibbertigibbet@org.sunbird.msg.slack”
}
Response: Status 400

Indicates that the room was not created because of an error encountered when processing the request. The error could be one of

  • ERR_ROOM_UNAVAILABLE: The room name chosen is unavailable
  • ERR_VISIBILITY_UNSUPPORTED: The chosen visibility is unsupported by the service
  • ERR_MEMBERSHIP_TYPE_UNSUPPORTED: The chosen joinability is unsupported by the service
  • ERR_VERSION_UNSUPPORTED: The room version selected is not supported by the service
{
“errcode”: “ERR_ROOM_UNAVILABLE”,
“err”: “Room with name ‘chalis-chor’ already exists”
}

Add/Remove/Ban member(s): POST /msg/client/v1/room/event/send?type=membership

This event adds/removes new members to the room using

  • RoomAddress
  • UserId
  • PrivilegeLevel (only for adding members)

Set the name/topic for the room: PUT /msg/client/v1/room/event/send?type=metadata

This event changes room metadata using

  • RoomAddress
  • Name/Topic

User-to-room messaging

Send message event: POST /msg/client/v1/room/msg/send?msgId=<msgId>

Sends a message to a room. The interface supports sending multiple types of messages to a room. Not every service implementation will support the universe of message types. It is up to the client to handle errors when sending messages which are unsupported by the server.

Request

Parameter

Type

Description

Query parameters

msgId

String

A client generated message identifier which is unique across messages. This is used to provide idempotency guarantees.

JSON Body parameters

type

String

The type of event being sent to the room. Required

Must be org.sunbird.msg.event.room.message

roomAddress

String

The room to which the message is to be sent. Required

msg

MessageObject

An event containing the body of the message to send to the room. Required

MessageObject

Parameter

Type

Description

msgtype

Enum

Type of message being sent. Required

Could be any one of org.sunbird.msg.text,

org.sunbird.msg.action,

org.sunbird.msg.notice,

org.sunbird.msg.image,

org.sunbird.msg.audio, org.sunbird.msg.video,

org.sunbird.msg.contact,

org.sunbird.msg.location,

org.sunbird.msg.file

body

String

A string containing the message body to send to the room.

Example
POST /msg/client/v1/room/msg/send?msgId=hep146j1982h1019dngwcn985ahcd928
Content-type: application/json
{
“type”: “org.sunbird.msg.event.room.message”,
“roomAddress”: “flibbertigibbet@org.sunbird.msg.slack”,
“msg”: {
“msgtype”: “org.sunbird.msg.text”,
“body”: “hello world!”
}
}
Response: Status 200

Indicates that the message was sent successfully to the room and returns the eventId.

{
“eventId”: “greatsuccess!@org.sunbird.msg.slack”
}
Response: Status 400

Indicates that the message was not sent because of an error encountered when processing the request. The error could be one of

  • ERR_ROOM_INVALID: The roomAddress given is not a valid room.
  • ERR_EVENT_TYPE_INVALID: The event type sent is not a message event
  • ERR_EVENT_TYPE_UNSUPPORTED: The event type sent is not supported by the service
  • ERR_MESSAGE_TYPE_INVALID: The message type sent is not a valid message type
  • ERR_MESSAGE_TYPE_UNSUPPORTED: The message type sent is not supported by the service
  • ERR_MESSAGE_INVALID: The message sent is not a valid message of msgtype
{
“errcode”: “ERR_MESSAGE_INVALID”,
“err”: “body field is required for messages of type org.sunbird.msg.text”
}

Send another event type: POST /msg/client/v1/room/event/send?type=<eventType>

  • RoomAddress
  • EventType
  • EventBody

Fetch message events: GET /msg/client/v1/room/msg/list

Fetches messages from a room. Messages in a room are paginated. This interface provides support for both forward and backward pagination. The interface may return types of messages which may not be supported by the client. The client MUST fallback to display the textual representation of a message type which it does not support.

Request

Parameter

Type

Description

JSON Body parameters

type

String

The type of event being fetched from the room. Required

Must be org.sunbird.msg.event.room.message

roomAddress

String

The room from where the messages are to be read. Required

from

String

A token pointing to the point where to start reading messages from. Required

This parameter is typically set from the response to a previous /room/msg/list call. It also takes two sentinel values start and end.

start lists messages from the beginning of the room’s history, while end lists messages from the end of the room’s history.

to

String

A point to where to stop reading messages. Can be a pagination token or an eventId

dir

Enum

Direction in which to list messages. One of f or b

limit

Int

Maximum number of messages to read. Defaults to 10. The server may choose to return fewer messages than the limit specified.

Example
GET /msg/client/v1/room/msg/list?msgId=hep146j1982h1019dngwcn985ahcd928
Content-type: application/json
{
“type”: “org.sunbird.msg.event.room.message”,
“roomAddress”: “flibbertigibbet@org.sunbird.msg.slack”,
“from”: “end”,
“dir”: “b”,
“limit”: 15
}
Response: Status 200

Returns messages from the room starting at from and ending with a token to request the next batch of messages.

Parameter

Type

Description

start

String

The token where the pagination starts. This will be the token passed in from.

end

String

The token where the pagination ends. This token can be passed as the from parameter in the next call to /room/msg/list

dir

String

The direction in which the pagination is proceeding

messages

List(MessageEvent)

A list of message events.

MessageEvent

Parameter

Type

Description

type

String

The type of event being fetched from the room. Required

Must be org.sunbird.msg.event.room.message

roomAddress

String

The roomAddress where the event was sent

eventId

String

A unique identifier for the event. This can be used by clients to de-duplicate events if needed.

sender

String

A fully-qualified user id of the message sender

sentTs

Int

The unix-epoch timestamp on the server when the message was sent.

msg

MessageObject

A message object defined in the Send message endpoint

Example
{
“start”: “end”,
“end”: “jbtxl-w891837kdfg-k127-8428kdkdghj-k12473”,
“dir”: “b”,
“messages”: [{
“type”: “org.sunbird.msg.event.room.message”,
“roomAddress”: “flibbertigibbet@org.sunbird.msg.slack”,
“eventId”: “jbtxl-w894375wenv-k319-2747ncijrfhs-k16371”,
“sender”: “sabu@org.sunbird.msg.slack”,
“sentTs”: 1444903112581,
       “msg”: {
“msgtype”: “org.sunbird.msg.text”,
           “body”: “hello world!”
}
}, {
“type”: “org.sunbird.msg.event.room.message”,
“roomAddress”: “flibbertigibbet@org.sunbird.msg.slack”,
“eventId”: “jbtxl-w891837kdfg-k127-8428kdkdghj-k12473”,
“sender”: “chacha_chaudhary@org.sunbird.msg.slack”,
“sentTs”: 1444903111337,
“msg”: {
“msgtype”: “org.sunbird.msg.text”,
“body”: “hello world!”
}
}]
}
Response: Status 400

Indicates that messages could not be retrieved because of an error encountered when processing the request. The error could be one of

  • ERR_ROOM_INVALID: The roomAddress given is not a valid room.
  • ERR_FROM_INVALID: The start point from where to read messages is not valid.
  • ERR_TO_INVALID: The end point where to stop reading messages is not valid.
  • ERR_DIR_INVALID: The direction given is not valid.

{
“errcode”: “ERR_FROM_INVALID”,
“err”: “The from field value: `latest` is not valid.”
}

Leave the room