Close mobile menu

API Reference

OverviewSMSVoice CallingVoice MessagingConversationsOmnichannel WidgetNumbersPartner AccountsVerifyMMSHLRReportingBalanceLookupContactsGroups

Client SDK Early Access



Introduction

Client SDK is a browser based SDK written in JavaScript and powered by WebRTC Technology. Using the Client SDK, Developers can integrate voice calling capabilities into their core applications. Please note that in order to control the behavior of incoming/outgoing calls, Voice API’s call flows can be used to provide the expected call logic. Please check our Voice Calling API for more information


Installation

The client SDK is distributed on npm. To install the SDK and start using it in your app, install the package @messagebird/client

npm install @messagebird/client
# Or if you use yarn
yarn add @messagebird/client

Authentication

In order to authenticate your Clients to use our platform, There are 2 steps that are needed:

  1. Obtain Access Key from Messagebird.
  2. Assign capabilities to your Clients & generate JSON Web token (JWT)

The Following section explains the details of each of the previous steps:

Obtain an Access Key

Once you create a Messagebird account, you will be able to create, manage and retreive your Access keys from the Messagebird Developers Dashboard.

Assign Capabilities to Clients & Generate JWT

Capabilities

Clients can be given capabilities to perform specific actions. Capabilities are represented by a capability and their attributes. The attributes are represented as URL parameters. Example structure of a capability: capability?attribute1=foo&attribute2=bar.

In order to provide control on what your Client can do, currently our Client SDK supports 2 different capabilities:

  • client.outgoing allows the Client to place an outgoing call
  • client.incoming allows the Client to receive an incoming call

You can choose to add either or both of them to your JWT.

client.outgoing

This capability gives the Client the capability to initiate an outgoing call to our platform, upon which a call flow will be executed to process the call and apply the desired call logic. At this moment, a call can only be processed by a Voice API Call flow. In the future, Flow Builder will also be supported in order to execute the desired call logic.

attributetypedescriptionrequired
callProcessorstringThe type of service that should process this call. At this moment we only support callflow, which can be created through the Voice-API.Yes
callProcessorIdstringThe ID of the call flow object above. This ID can be retrieved through Voice-API and will also be represented to you when creating the call flow.Yes
variablesstringAn urlencoded object of parameters that will be sent the incoming call processor (key\<>value).No
identitystringThe alpha-numeric caller-id of this connection. This will show up in the calls/legs in the API and will show up as source in fetchCallFlow steps and webhooks. When empty, anonymous will be used. Max-length: 30.No

An example of a client.outgoing can be found on the right. This example would process the call with a call-flow with ID de3ed163-d5fc-45f4-b8c4-7eea7458c635. The client would be identified as "Bert" and the variables "foo=bar&bar=foo" would be passed through with a call flow fetch. Note that the variables will show up in the call flow fetch also in the variables parameter.

client.incoming

This capability gives the client the capability to receive an incoming call from our platform via the Client SDK. Calls can be forwarded to the Client by using client:foobar in the destination parameter when doing a transfer-step or when creating an outgoing call through the Voice API.

attributetypedescriptionrequired
identitystringThe alpha-numeric identity of this connection. This identity can be used to receive calls trough the destination parameter like client:foobar, if the identity would be foobar. Max-length: 30.Yes

Generating the JSON Web Token

The payload of a JWT should contain accessKeyID, capabilities, iat and exp.

The token should be signed with the MessageBird accessKey. Please make sure that the accessKey is not exposed on the client SDK side or in the JWT itself, only use it for signing the JWT. Please refer to JSON Web Tokens for help with generating JWT's in your current programming language.

{
"accessKeyID": "example", // ID of a MessageBird AccessKey
"capabilities": [
"client.outgoing" +
"?callProcessor=callflow" +
"&callProcessorId=de3ed163-d5fc-45f4-b8c4-7eea7458c635" +
"&identity=Bert" +
"&variables=foo%3Dbar%26bar%3Dfoo"
],
"iat": 1516239022, // issued at
"exp": 1516239022, // Expiry time
}

Initializing a New MessageBirdClient

The next step after the authentication is done, is to instantiate a new MessageBirdClient. You will use the MessageBirdClient instance to set up a connection to our platform, and to initiate and receive calls. After instantiating the client, call client.setup() to start the connection to our platform and be able to make and receive calls. A valid JWT has to be passed to the .setup() method for the authentication to succeed.

import { MessageBirdClient } from '@messagebird/client';
/**
* The "refreshToken" can be called multiple times over time.
* This function should return a promise that resolves with a valid JWT.
* If needed, you can also fetch a new JWT within this function.
* */
const refreshToken = async () => {
if (isTokenExpired(myCurrentToken)) {
return await refreshToken();
}
return myCurrentToken;
}
const client = new MessageBirdClient({
refreshToken,
});
// start a connection to the MessageBird WebRTC API
client.setup({ jwt: myCurrentToken })

Handling client status updates

The client will emit a status event when the connection status of the client changes. Possible status values are:

valueDescription
offlinethe initial status of the client after it is initialized . Calling destroy() resets the status to initial.
connectingthe client is in the process of establishing a connection to our platform
connectedthe client is connected to our platform and ready for initiating and receiving calls
errorAn error occured. The error event is also fired containing the error that occured
const handleStatusChange = (status) => {
switch(status) {
case 'connected':
break;
case 'error':
break;
case 'connecting':
break;
case 'initial':
break;
}
};
// Start listening for status updates
client.on('status', handleStatusChange);
// Stop receiving updates for status changes
client.removeEventListener('status', handleStatusChange);

Handling client errors

If the connection to our platform fails after calling setup(), or if the client disconnects over time (for example when the browser loses internet connection), the client will emit an error event. Use this event to determine what your application should do next to ensure the client can reconnect to our platform.

These are the possible errors:

CodeMessageDescription
403Forbidden, Token not found or expired.JWT has expired or missing in the .setup() method
406Invalid identity provided in client.incoming capability, only alphanumeric and underscore characters are allowedclient.incoming identity has to be alphanumeric characters only so that the Client can be identified by our platform and receive incoming calls.
500Internal errorAn unexpected internal error occurred. See the error object for more information
const handleClientError = (error) => {
switch(error.code) {
case 403:
// Unauthorized. Try refreshing the JWT and try again
break;
case 406:
// Invalid identity. An error in "identity" capability of the the JWT
break;
case 500:
// An internal error on our platform.
break;
}
}
client.on('error', handleClientError);
client.removeEventListener('error', handleClientError);

Starting a new Call

The client.startCall() method can be called to start an outgoing call. Any additional data can be passed as arguments to the '.startCall()' method. This method will throw an error if you attempt to start a call while the client is not yet connected to our platform.

const { call } = client.startCall({
// Any additional data can be passed as arguments to the 'startCall' method
conference: 'Test conference',
to: '+31612345678',
});
call.on('status', handleCallStatus);
call.on('error', handleCallError);
call.endCall();

Handling an Incoming Call

Listening to the client.on('incoming') event will allow you to respond to incoming calls on your UI. The callback function retrieves an instance of IncomingCall as its first argument, which can be used to respond to the incoming call by either calling:

  • .accept() to accept the incoming call.
  • .reject() to reject the incoming call.
client.on('incoming', incomingCall => {
// Update your UI to display an incoming call.
// Accept the incoming connection and start a call
const call = incomingCall.accept();
// Reject the incoming call
incomingCall.reject();
});
client.on('canceled', () => {
// The incoming call was hung up from the other side.
// Here, you can update UI to stop showing the incoming call.
})

Managing active calls

After having accepted an incoming call, or started an outgoing call, you can access the call instance. You can use this instance to subscribe to updates about the status of the call, and to modify the state of the call.

Handling call status updates

Just like the client, the call instance will emit status event that notifies you when the status of a call has changed. The status of the call can have the following values:

valueDescription
connectingCall is in the process of being connected
acceptedCall is accepted by the called party
confirmedThe call is accepted by called party and connection is established
failedCall failed. An error event was emitted containing details of the failure
endedCall ended without any failures
ringingCall is ringing on the called party end
const handleStatusChange = (status) => {
// Update the UI based on the status.
setClientStatus(status);
switch(status) {
case 'connecting':
case 'accepted':
case 'confirmed':
case 'failed':
case 'ended':
case 'ringing':
}
}
call.on('status', handleStatusChange);
call.removeEventListener('status', handleStatusChange);

Handling call errors

When a call fails to establish, or unexpectedly disconnects during the call, an error event will be emitted notifying you of the failure reason.

const handleCallError = (error) => {
// Update UI based on the error that occurred within the call
}
call.on('error', handleCallError);
call.removeEventListener('error', handleCallError)

Audio Management

Enumerating devices

It is possible to enumerate the user's available media devices using the MediaSources class that is exposed by the SDK. This class exposes a public method called get() which will return the list of user devices, as well as a getter method called devices which performs the same function.

import { MediaSources } from '@messagebird/client';
const sources = new MediaSources();
// Enumerates the list of devices
const devices = sources.get()
// Provides the same device list as the above get() call
const theSameDevices = sources.devices

Because available devices may change over time as users connect/remove equipment, the MediaSources class makes available an event listener method on which accepts only the devicechange event. A corresponding off method can be used to remove any registered callbacks for this event, and it takes the same arguments. The callback to this method returns the full list of devices that are currently available, any handling of differences is therefore left up to the author.

import { MediaSources } from '@messagebird/client';
const sources = new MediaSources();
function handleChange(devices) {
console.log({ devices })
}
sources.on('devicechange', handleChange)
sources.off('devicechange', handleChange)

Device listing methods, including the callbacks to the event listeners, will always respond with the following structure where MediaDeviceInfo follows the standard implementation. Note that video input streams are not currently supported by the SDK, but are still available in the enumeration methods.

{
inputs: {
audio: MediaDeviceInfo[]
video: MediaDeviceInfo[]
};
outputs: {
audio: MediaDeviceInfo[]
};
}

Selecting devices

Once devices have been enumerated, it is possible to select a particular device to be used in the call by using the setInputSource method available on a call object. To learn how to initialize a call, and therefore have access to this interface, see Starting a new Call.

The setInputSource method accepts a single argument that specifies the MediaStreamConstraints that should be used. After enumerating available devices, the identifiers of the user's media sources will be available, and these can be used to select specific devices.

const sources = new MediaSources();
const [anAudioDevice] = sources.devices.audio;
call.setInputSource({ audio: { deviceId: anAudioDevice.deviceId } })

The setOutputSource method of a call allows you to specify the audio output that should be used on a particular call. Because the selection of this device must be unique, this method only accepts the deviceId property of a MediaSource.

const sources = new MediaSources();
const [anAudioDevice] = sources.devices.audio;
call.setOutputSource(anAudioDevice.deviceId)

Muting and unmuting audio

You can mute your microphone (or the selected audio device) by calling the .mute() method on a call. If you need to unmute, .unmute() can be called on the same call instance. In both cases muted event is fired when the change has been successfully applied. The event has the following values:

valueDescription
trueThe audio device is muted
falseThe audio device is not muted
const handleMutedChange = (isMuted) => {
// Update UI to show a call was muted or unmuted.
}
call.on('muted', handleMutedChange);
call.removeEventListener('muted', handleMutedChange)
call.mute(true); // Mute the call
call.mute(false); // unmute the call

Sending digits

To send DTMF digits during a call, .sendDigits() method has to be called on call instance. The digits parameter should be a string containing only valid DTMF digits (0-9, *, and #).

// Press "1" on the keypad.
call.sendDigits('1');
Next upApi

Questions?

We’re always happy to help with code or other doubts you might have! Check out our Quickstarts, API Reference, Tutorials, SDKs, or contact our Support team.

Cookie Settings