The Sinch SDK is a product that makes adding voice calling to mobile apps easy. It handles all the complexity of signaling and audio management while providing you the freedom to create a stunning user interface.

This document provides an overview for developers integrating with Sinch SDK for the first time. It outlines the prerequisites and guides you through the process of setting up and answering calls.

Please see the Reference Documentation for a comprehensive description of all the classes.

First time setup

Below is a step-by-step guide on setting up the Sinch SDK for the first time.

Register an Application

  1. Register a Sinch Developer account at
  2. Setup a new Application using the Dashboard where you can then obtain an Application Key and an Application Secret.


The Sinch SDK can be downloaded at It contains: the library aar, this user guide, reference documentation, and sample apps.

Add the Sinch library

The Sinch SDK library is distributed in AAR format. To use it in your project either:

Build Requirements

We recommend using:

SDK comes with set of sample applications covering various aspects of SDK use, with sinch-rtc-sample-video-push being probably the most complex, since in addition to other tools, it highlights use of the managed push notification via FCM. Thus, we recommend to look into its build.gradle file for reference about versions of build settings / support library versions etc.

Running ProGuard

If you are using ProGuard, we bundle an example proguard-project.txt file that makes sure that the Sinch SDK will work as expected.


A minimum set of permissions are needed for the app to use the Sinch SDK. These are specified in the AndroidManifest.xml file. If the calling functionality will be used, all five permissions listed here are needed. However, if the calling functionality isn’t used, the last three (RECORD_AUDIO, MODIFY_AUDIO_SETTINGS and READ_PHONE_STATE) can be omitted.

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

Note: By default, the Sinch SDK hangs up any Sinch call if the regular phone app has an active call. This functionality requires the permission READ_PHONE_STATE. However, if this default functionality isn’t wanted, turn it off by calling sinchClient.getCallClient().setRespectNativeCalls(false); and the permission READ_PHONE_STATE is not needed.

Verify manifest in runtime during development

To verify that the manifest has the necessary permissions the sinchClient.checkManifest() method can be used. This method should be called before starting the client and will throw an exception if the manifest isn’t setup correctly. sinchClient.checkManifest() should only be called during development. When the application is ready for release the method call can safely be removed.

Note: This method takes into consideration which features the app supports (for example, calling, respecting native calls, and so on). Call sinchClient.checkManifest() after the setup but before the start of the SinchClient.

Android Sinch SDK 3.14.x Changes

New Build Requirements

To bring the best experience with our SDK and facilitate its long-term maintenance, we had to change the build tools requirements. We recommend using:

SDK comes with set of sample applications covering various aspects of SDK use, with sinch-rtc-sample-video-push being probably the most complex, since in addition to other tools, it highlights use of the managed push notification via FCM. Thus, we recommend to look into its build.gradle file for reference about versions of build settings / support library versions etc.

VideoController API Changes

New API: setLocalVideoZOrder

VideoController now exposes new API to control overlay of remote/local views.

    /** Sets whether local video (preview from camera) should be rendered on top of remove video view (default behavior) or vice versa in case views are overlapping.
     * @param onTopOfRemoteView if set to false will make remove video rendered on top of preview.
    void setLocalVideoZOrder(boolean onTopOfRemoteView);

When two video views are overlapping, one need to select which one should be rendered on top. By default it’s local video (preview from the camera), but when called with onTopOfRemoteView = false, this method will render remote view over local, allowing design when, say, local preview occupies full screen, and remote is floating ‘above’.

Changed API: setVideoFrameListener

    void setVideoFrameListener(VideoFrameListener listener);

This API was used to allow to get access to inbound video to, say, make a screenshot of it. It’s been changed to:

    /** Sets a listener for the remote video frames. Blocks rendering. In-place modification of
     * provided I420 frame would affect rendering. If heavy operation is required, which does not
     * affect rendering, e.g. saving screen-shot in JPEG - spawn a work thread and work with
     * a copy of the frame. See {@Link VideoUtils} for I420 -> NV21 conversion.
     * <p>See {@link RemoteVideoFrameListener} for more information.</p>
     * IMPORTANT: set to null when listener is no longer needed - it will increase performance by
     * eliminating otherwise necessary conversion from captured texture-based frame into
     * memory buffer-backed I420 frame.
    void setRemoteVideoFrameListener(RemoteVideoFrameListener listener);

Sample application sinch-rtc-sample-video-screenshot showcases the use of this API. Rather than just having a copy of the stream, you can now modify it before it’s been rendered. NB: modification should be performed in-place, please read reference manual.

Removed API: setBorderColor()

    void setBorderColor(float r, float g, float b);

This API is no longer required, since video views container obtained via VideoController’s getLocalView() and getRemoteView() have transparent letterboxing, and only part of the container that is covered by video is rendered. That allows use of variety of design approaches, like having a background picture below the video rather than just single colored border.

Sinch client

The SinchClient is the Sinch SDK entry point. It is used to configure the user’s and device’s capabilities, as well as to provide access to feature classes such as the CallClient and AudioController.

Create a SinchClient

// Instantiate a SinchClient using the SinchClientBuilder.
android.content.Context context = this.getApplicationContext();
SinchClient sinchClient = Sinch.getSinchClientBuilder().context(context)
                                                  .applicationKey("<application key>")
                                                  .applicationSecret("<application secret>")
                                                  .userId("<user id>")

The Application Key and Application Secret are obtained from the Sinch Developer Dashboard. See Production and Sandbox Environments for valid values for environmentHost. The User ID should uniquely identify the user on the particular device.

Note: All listener callbacks emitted from the Sinch SDK are invoked on the same thread that the call to is made on. If the invoking thread is not the main-thread, it needs to have an associated Looper.

Specify capabilities

The SinchClient can be configured to enable or disable certain functionality. Please see the Reference for a comprehensive description of each capability.

The following example shows how to setup the client with both voice calling and managed push notifications enabled.

// Specify the client capabilities. 
// or

Calling startListeningOnActiveConnection allows your application to receive incoming calls and messages without using push notifications.

Note: If the application is meant to only make outgoing calls but not receive incoming calls, don’t call startListeningOnActiveConnection or setSupportManagedPush. Outgoing calls can be made after calling the start method.

Start the Sinch client

Before starting the client, add a client listener (see Reference documentation):

sinchClient.addSinchClientListener(new SinchClientListener() {

    public void onClientStarted(SinchClient client) { }

    public void onClientStopped(SinchClient client) { }

    public void onClientFailed(SinchClient client, SinchError error) { }

    public void onRegistrationCredentialsRequired(SinchClient client, ClientRegistration registrationCallback) { }

    public void onLogMessage(int level, String area, String message) { }


Terminate the Sinch client

When the app is done using the SinchClient, it should be stopped. If the client is currently listening for incoming events, it needs to stop listening as well. After terminateGracefully is called, any object retrieved directly from the client object (that is, CallClient and AudioController) is considered invalid.

Terminating the client:



The Sinch SDK supports four types of calls: app-to-app (audio or video), app-to-phone, app-to-sip and conference calls. The CallClient is the entry point for the calling functionality of the Sinch SDK.

Calls are placed through the CallClient and events are received using the CallClientListener. The call client is owned by the SinchClient and accessed using sinchClient.getCallClient(). Calling is not enabled by default.

Enable calling with the following method before starting the SinchClient:


Set up an app-to-app call

Use the CallClient to start the call (the callUser method). Pass the user identifier of the callee (the user receiving the call) to the call method, so that Sinch services can connect the call to the callee.

CallClient callClient = sinchClient.getCallClient();
Call call = callClient.callUser("<remote user id>");
// Or for video call: Call call = callClient.callUserVideo("<remote user id>");

A call object is returned, containing details about the participants in the call, call details such as start time, call state, possible errors, and so on.

Assuming the callee’s device is available, the method onCallProgressing is called on the CallListener. It notifies the application that the outgoing call is progressing. If a progress tone should be played, this is where it should be started.

When the other party answers, the onCallEstablished method is called. Now, the users can start talking. If a progress tone was previously played, it should be stopped now.

Set up an app-to-phone call

An app-to-phone call is a call that is made to a phone on the regular telephone network. Setting up an app-to-phone call is not much different than setting up an app-to-app call. Instead of invoking the callUser method, invoke the callPhoneNumber method on the CallClient object. Sufficient funds must be available on the Sinch account and a valid phone number specified for the call to connect successfully. The phone number should be specified according to the E.164 number formatting ( recommendation and should be prefixed with a ‘+’. E.g. to call the US phone number 415 555 0101, the phone number should be specified as “+14155550101”. The ‘+’ is the required prefix and the US country code ‘1’ prepended to the local subscriber number.

Placing an app-to-phone call requires a developer account with credits. Topping up credits can be done on the Account page. Credits are used each time an app-to-phone call is placed and the balance history is updated after each call.

App-to-phone calls can be tested by calling the following test number: +46000000000. When placing a call to this number, you will hear a voice prompt stating that the call has been connected, and shortly after that the call will automatically be ended.

Set up an app-to-sip call

An app-to-sip call is a call that is made to a SIP server. Setting up an app-to-sip call is not much different from setting up an app-to-app call. Instead of invoking the callUser method, invoke the callSip method on the CallClient object. The SIP identity should be in the form “user@server”. By convention, when passing custom headers in the SIP call, the headers should be prefixed with “x-”. If the SIP server reported any errors, the CallDetails object will provide an error with the SIP error type.

Set up a conference call

A conference call can be made to connect a user to a conference room where multiple users can be connected at the same time. The identifier for a conference room may not be longer than 64 characters.

CallClient callClient = sinchClient.getCallClient();
Call call = callClient.callConference("<conferenceId>");

It is also possible to connect users to a conference call via the Sinch REST API.

Handle incoming calls

To answer calls, the application must be notified when the user receives an incoming call.

Add a CallClientListener to the CallClient to act on the incoming calls. The CallClientListener is notified using onIncomingCall as calls come in to the device.

CallClient callClient = sinchClient.getCallClient();

When the incoming call method is executed, the call can either be connected automatically without any user action, or it can wait for the user to press the answer or the hangup button. If the call is set up to wait for a user response, we recommended that a ringtone is played to notify the user that there is an incoming call.

public void onIncomingCall(CallClient callClient, Call call) {
    // Start playing ringing tone

    // Add call listener

To get events related to the call, add a call listener. The call object contains details about participants, start time, potential error codes, and error messages.

Incoming video call

When incoming call is a video call, the onIncomingCall callback will be executed, just like for the incoming audio call. The CallDetails object provides a isVideoOffered() method to check whether the call offers a video track. See the Video calling section for details on how to add video views.

Answer incoming call

To answer the call, use the answer method on the call to accept it. If a ringtone was previously played, it should be stopped now.

User presses the answer button:

// User answers the call

// Stop playing ringing tone

Now, the clients on both ends establish the connection. When the call is established and the voice streams are running in both directions, the onCallEstablished listener method is called.

Decline incoming call

If the call should not be answered, use the hangup method on the call to decline. The caller is notified that the incoming call was denied. If a ringtone was previously played, it should be stopped now.

User presses the hangup button:

// User does not want to answer

// Stop playing ringing tone

Disconnecting a Call

When the user wants to disconnect an ongoing call, use the hangup method. Either user taking part in a call can disconnect it.

Hanging up a call:


When either party disconnects a call, the application is notified using the call listener method onCallEnded. This allows the user interface to be updated, an alert tone to be played, or similar actions to occur.

A call can be disconnected before it has been completely established.

Hanging up a connecting call:

// Starting a call
Call call = callClient.callUser("<remote user id>");

// User changed his/her mind, let’s hangup

Volume control

To make sure that the volume of the call can be modified by the hardware volume controls, setVolumeControlStream(AudioManager.STREAM_VOICE_CALL) must be called on the Activity where the call is handled. Make sure that volumeControlStream is reset to a suitable value when the call has ended.

For example, after creating a call (using CallClient.callUser) or when answering a call (using Call.answer()) you should call setVolumeControlStream(AudioManager.STREAM_VOICE_CALL);.

When the call ends, set the volume control stream back to it’s previous value. For example in your implementation of CallListener:

    public void onCallEnded(Call call) {

Video calling

Setting up a video call

Just like audio calls, video calls are placed through the CallClient and events are received using the CallClientListener. The call client is owned by the SinchClient and accessed using sinchClient.getCallClient(). Calling is not enabled by default. For a more general introduction to calling with the SinchClient, see Calling.

Showing the video streams

Once you have created a VideoCallListener and added it to a call, the onVideoTrackAdded() method will be called.

    public void onVideoTrackAdded(Call call) {
        // Get a reference to your SinchClient, in the samples this is done through the service interface:
        VideoController vc = getSinchServiceInterface().getVideoController();
        View myPreview = vc.getLocalView();
        View remoteView = vc.getRemoteView();

        // Add the views to your view hierarchy

After the call has ended, don’t forget to remove the views from your view hierarchy again.

    public void onCallEnded(Call call) {
        // Remove Sinch video views from your view hierarchy

Pausing video stream

To pause the local video stream, use the pauseVideo() method on the call.

    // User pause the video stream 

Resuming video stream

To resume the local video stream, use the resumeVideo() method on the call.

   // User resumes the video stream 

Pausing video stream delegates

Once you have created a VideoCallListener and added it to a call, the onVideoTrackPaused() method will be called when the remote user pause the video stream.

   public void onVideoTrackPaused(Call call) {
        // Implement what to be done when remote user pause video stream.

Resuming video stream delegates

Once you have created a VideoCallListener and added it to a call, the onVideoTrackResumed() method will be called when the remote user resumes the video stream..

   public void onVideoTrackResumed(Call call) {
        // Implement what to be done when remote user resumes video stream.

Video content fitting and aspect ratio

How the remote video stream is fitted into a view can be controller by the setResizeBehaviour() method with possible arguments VideoScalingType.ASPECT_FIT, VideoScalingType.ASPECT_FILL and VideoScalingType.ASPECT_BALANCED. The local preview will always use VideoScalingType.ASPECT_FIT.

Switching capturing device

The capturing device can be switched using videoController.setCaptureDevicePosition(int facing) with possible values Camera.CameraInfo.CAMERA_FACING_FRONT and Camera.CameraInfo.CAMERA_FACING_BACK. Use videoController.toggleCaptureDevicePosition() to alternate the two.

Accessing video frames of the remote streams

The Sinch SDK can provide access to raw video frames via a callback function. This callback can be used to achieve rich functionality such as applying filters, adding stickers to the video frames, or saving the video frame as an image.

Your video frame handler needs to implement VideoFrameListener interface by implementing the onFrame() callback. Note that it is important to explicitly release the video frame by calling release().



    public class YourVideoFrameHandler implements VideoFrameListener {
        public synchronized void onFrame(String callId, VideoFrame videoFrame) {
        ... // Process videoFrame
        videoFrame.release(); // Release videoFrame

Use setVideoFrameListener() to register your video frame handler as the callback to receive video frames.


    YourVideoFrameHandler videoFrameHandler = new YourVideoFrameHandler();
    VideoController vc = getSinchServiceInterface().getVideoController();

Converting video frame from I420 to NV21

The Sinch SDK provides a helper function to convert the default I420 frame to NV21 Frame, which is handy to work with when you need to save it as an image on Android. Use VideoUtils.I420toNV21Frame(VideoFrame) for the conversion. Note that this helper does NOT release the original I420 video frame.


    import; // To use I420toNV21Frame

    VideoFrame videoFrame = ... // Get the video frame from onFrame() callback
    VideoFrame nv21Frame = VideoUtils.I420toNV21Frame(videoFrame);

    YuvImage image = new YuvImage(nv21Frame.yuvPlanes()[0].array(),

Push notifications

When an application is not running, or the Active Connection feature is not enabled, the user must be notified of an incoming call by a push notification.

By invoking setSupportManagedPush(true) the Sinch SDK will automatically register to Firebase Cloud Messaging and the Sinch backend will initiate push messages to your application when needed. This feature requires Google Play Services on the device. If you distribute your application through other channels than Google Play, push notifications will not be available on devices that do not have Google Play Services.

If using the Sinch backend and Google Cloud Messaging is not viable in the application, please see Push Notifications sent via your application server and Active connection.

As a developer, you will be responsible for implementing the code that receives the FCM push message. For an example implementation, please see the sample app “Sinch Push” which is bundled with the SDK.

Sinch SDK moved from deprecated Google Cloud Messaging (GCM) to it’s most up-to-date and Google-recommended version Firebase Cloud Messaging (FCM), which requires client app to be modified in accordance with the Google’s official GCM to FCM migration guide

The following sections cover how to support receiving calls and messages via push notifications.

FCM configuration file required (google-services.json)

You can add Firebase to your app either semi-autimatically using Android Studio, or manually following this step-by-step official guide. In brief, to perform manual setup you first need to register your application in firebase console. If you already have GCM project, the console will prompt you to import it as new Firebase Cloud Messaging project. Register your application using the console, and download relevant google-services.json into your project’s main folder. More information about adding Firebase to your Android app can be found here

Sample SDK projects sinch-rtc-sample-push and sinch-rtc-sample-video-push will require you to supply your own google-services.json in order to be built. In the absence of this file gradle will show relevant error with explanation and relevant links and stop the build. That google-services.json file is the main mean of automatization of support of Firebase services to your app. Android Studio’s ‘’ plugin parses and adds relevant resources and permissions to your applications manifest automatically.

Permissions required

Unlike GCM setup, FCM application developer does not need to manually add any permission to application manifest. For relevant changes in you application’s manifest when migrating from GCM to FCM please consult official GCM to FCM migration guide

Enable push notifications

To enable push notifications, set the following capability before starting the Sinch client:

NOTE: You must catch the MissingGCMException if you distribute your app to devices without Google Play Services.

NOTE: Using setSupportManagedPush(true) will register a token with Firebase Cloud Messaging using a Sender ID connected to Sinch, which will NOT unregister your own token, so you CAN use Firebase Cloud Messages for your own purpose filtering them in onMessageReceived(RemoteMessage remoteMessage) method of your FCM Listening Service using Sinch helper API SinchHelpers.isSinchPushPayload.

 public class FcmListenerService extends FirebaseMessagingService {

public void onMessageReceived(RemoteMessage remoteMessage){
    if (SinchHelpers.isSinchPushPayload(remoteMessage.getData())) {
        // it's Sinch message - relay it to SinchClient
    } else {
        // it's NOT Sinch message - process yourself

Explicit push token registration

There are certain situations where it is either desirable to explicitly register push token and/or get assurance that the push token is indeed registered, e.g.:

Both situation should be handled with using new ManagedPush API available via Beta interface:

       public ManagedPush getManagedPush(String username) {
            // create client, but you don't need to start it 
            // retrieve ManagedPush
            return Beta.createManagedPush(mSinchClient);

The former situation is showcased in in sinch-rtc-sample-push and sinch-rtc-sample-video-push sample applications. The activity implements PushTokenRegistrationCallback interface,

       public class LoginActivity extends BaseActivity implements SinchService.StartFailedListener, PushTokenRegistrationCallback {

       private void loginClicked() {
              if (!mPushTokenIsRegistered) {

       public void tokenRegistered() {
              mPushTokenIsRegistered = true;

       public void tokenRegistrationFailed(SinchError sinchError) {
              mPushTokenIsRegistered = false;
              Toast.makeText(this, "Push token registration failed - incoming calls can't be received!", Toast.LENGTH_LONG).show();

And the UI andvances to the next activity only when both conditions are met: - the SinchClient is started; - the push token is registered

       private void nextActivityIfReady() {
        if (mPushTokenIsRegistered && getSinchServiceInterface().isStarted()) {
            //here you can either go the next activity to place the call, or terminate SinchClient and still be able to 
            //receive incoming calls, since the push token is registered.

The latter situation, when application is notified by the Firebase service that the push tokens should be refreshed, can be detected in the same FcmListenerService where push notification messages are received. Override onNewToken() method and re-register push tokens there.

       public class FcmListenerService extends FirebaseMessagingService {

       public void onNewToken(String newToken) {
       // newToken supplied here is the token for `default` FCM project.
       // but the mere fact of receiving this callback informs the application
       // that ALL tokens should be re-acquired

Where instanceOfMyPushTokenRegistrationClass.registerPushToken() behaviour is defined by the same pattern as in the previous situation - call the ManagedPush.registerPushToken(final PushTokenRegistrationCallback callback) and wait for callback to decide how to proceed depending on reuslt.

Receive and forward push notifications to a Sinch client

For more details regarding how to implement receiving a FCM downstream message, please see the Android developer site for FCM.

Once you have received the RemoteMessage in your FirebaseMessagingService, forward it to the Sinch client using the method relayRemotePushNotificationPayload.

 // make sure you have created a SinchClient
 if (SinchHelpers.isSinchPushPayload(remoteMessage.getData())) {
 NotificationResult result = sinchClient.relayRemotePushNotificationPayload(remoteMessage.getData());
The returned result can be inspected to see whether the push was for an IM or a call using result.isMessage() and result.isCall().

Incoming call

If the payload that was forwarded to the Sinch client was for a call, the onIncomingCall callback will automatically be triggered as for any other call. The CallNotificationResult object provides details about participants, whether the call timed out and whether the call offers video.

Send and receive custom headers via Sinch managed push

The Sinch SDK supports adding custom headers in push notification messages when initiating a call, so developers do not need to implement their own push mechanism if they only need to deliver small pieces of information along the Sinch managed push between their app instances. The Sinch SDK allows up to 1024 bytes of custom headers.

Setting custom headers on the sender side when initiating a call:

 // setting up custom headers
 Map<String,String> headers = new HashMap<>();
 headers.put(“The first value is ”, “@123”);
 headers.put(“Custom value ”, “two!”);
 Call call = callClient.callUser(userId, headers);
If custom headers were supplied by call initiator, they can be retrieved from notification result using getHeaders() API:

 // make sure you have created a SinchClient
 if (SinchHelpers.isSinchPushPayload(remoteMessage.getData())) {
 NotificationResult result = sinchClient.relayRemotePushNotificationPayload(remoteMessage.getData());
 if (result.isCall()) {
 CallNotificationResult callResult = result.getCallResult();
 Map<String, String> customHeaders = callResult.getHeaders());

NOTE: It is possible to retrieve custom headers from the push message using SinchHelpers.queryPushNotificationPayload without starting the client.

 // SinchClient is not needed to be created at all!
 if (SinchHelpers.isSinchPushPayload(remoteMessage.getData())) {
 NotificationResult result = SinchHelpers.queryPushNotificationPayload(applicationContext, remoteMessage.getData());
 if (result.isCall()) {
 CallNotificationResult callResult = result.getCallResult();
 Map<String, String> customHeaders = callResult.getHeaders());
 // analyse headers, decide whether to process message/call and start Sinch client or ignore

Show local notifications for missed calls

When the push notification is enabled on a Sinch client, besides the incoming call notification, the Sinch SDK will also send a push notification for a canceled call when the caller cancels the call before it is answered. This gives developers a good opportunity to present local notifications for missed calls in their apps:

 NotificationResult result = sinchService.relayRemotePushNotificationPayload(payload);
 // handle result, e.g. show a notification for a missed call:
if (result.isValid() && result.isCall()) { CallNotificationResult callResult = result.getCallResult(); if (callResult.isCallCanceled()) { // user-defined method to show notification createNotification(callResult.getRemoteUserId()); } }

NOTE: if the message forwarded to the Sinch client happened to be call cancel message, the client arranges the termination of the call automatically resulting in CallListener.onCallEnded() event being triggered, allowing UI to handle canceling the call;

Unregister a device

If the user of the application logs out or performs a similar action, the push notification device token can be unregistered via SinchClient.unregisterManagedPush() to prevent further notifications to be sent to the device. Starting a client with setSupportManagedPush(true) will register the device again.

Active connection

If push notifications are not desired, the alternative is to use setSupportActiveConnectionInBackground(true) and then calling startListeningOnActiveConnection() to enable incoming calls and instant messages. Don’t forget to call stopListeningOnActiveConnection() when the user is no longer available for calls (for example if the application is no longer active).

Application authentication

A user identity must be provided when initiating a Sinch client. The first time the application instance and the Sinch client are running on behalf of a particular user, they are required to register against the Sinch service. This is mostly handled transparently by the Sinch SDK, but it works slightly differently depending on which authentication scheme you choose to use.

The step of registering a user identity against the Sinch service requires the application instance to be authenticated and authorized to perform the user registration. Once the application instance has successfully registered the user identity, it will also have obtained the necessary credentials to perform further authorized requests for that specific user, for example, calling.

Two different authentication schemes are available: authentication by client access to application secret and authentication supported by application server.

Authentication by client access to Application Secret

This application authentication scheme is based on giving the application direct access to the Application Secret, which enables the Sinch Client SDK in the application to self-sign an authorized request to perform user registration. Choosing this authentication scheme corresponds to initiating the Sinch client by using the factory method that takes both an Application Key and an Application Secret.

Using this authentication scheme is the quickest way to get started as the client application instances can directly perform authorized requests against the Sinch service.

Caution: It is not recommended to have the application secret in plain text in the source code in the release version of the application.

Authentication supported by application server

This application authentication scheme is based on the client application instance not having direct access to the Application Secret. Instead, when the Sinch client needs to perform an authorized request to register a user identity against the Sinch service, it needs to be provided with an authentication signature and a registration sequence to perform the registration. This should be provided by the application’s backend service, for example, by using a HTTP request over an SSL connection.

This scheme has the benefit of the application secret never being directly accessible by the client applications and provides a better level of security as well as flexibility.

Note: The need for the Sinch client to request an authentication signature and registration sequence is only required once per user and device–not on every application launch.

Figure 4. Authentication Supported by Application Server
Figure 4. Authentication Supported by Application Server

Generating the signature

The Application Server is responsible for generating a valid signature for each registration request that it accepts as a valid user registration. The sequence is a cryptographic nonce, and must be a monotonically increasing value. The signature is then generated as as follows (pseudogrammar):

string userId;
string applicationKey; // E.g. "196087a1-e815-4bc4-8984-60d8d8a43f1d"
string applicationSecret; // E.g. "oYdgGRXoxEuJhGDY2KQ/HQ=="
uint64 sequence = previous_sequence + 1; // E.g. previous_sequence = 0

string stringToSign = userId + applicationKey + sequence + applicationSecret;

// Use a Base64-encoder that don't introduce line-breaks, 
// or trim the output signature afterwards.
string signature = Base64.encode(SHA1.digest(stringToSign));

For example, in Java:

    // Generating the Signature - Java
    // import;
    // import org.apache.commons.codec.binary.Base64;

    String userId; 
    String applicationKey; // E.g. "196087a1-e815-4bc4-8984-60d8d8a43f1d";
    String applicationSecret; // E.g. "oYdgGRXoxEuJhGDY2KQ/HQ==";
    long sequence; // fetch and increment last used sequence

    String toSign = userId + applicationKey + sequence + applicationSecret;

    MessageDigest messageDigest = MessageDigest.getInstance("SHA-1");
    byte[] hash = messageDigest.digest(toSign.getBytes("UTF-8"));

    String signature = Base64.encodeBase64String(hash).trim();

Set up the Sinch client and provide authorization credentials for user registration

// Instantiate a SinchClient using the SinchClientBuilder,
// and don't specify the application secret, only the application key.
android.content.Context context = this.getApplicationContext();
SinchClient sinchClient = Sinch.getSinchClientBuilder().context(context)
                                                  .applicationKey("<application key>")
                                                  .userId("<user id>")


// SinchClientListener implementation
public void onRegistrationCredentialsRequired(SinchClient client, 
                                              ClientRegistration registrationCallback) {
    // This will on the first run for this user call onRegistrationCredentialsRequired on the client listener.
    // Perform API request to server which keeps the Application Secret.
    myApiService.getAuthorizedSignatureForUser("<user id>", new OnCompletedCallback() {
        public void onCompleted(String signature, long sequence) {
            // pass the signature and sequence back to the Sinch SDK
            // via the ClientRegistration interface.
            registrationCallback.register(signature, sequence);


Minimum requirements

You must have Android version 2.3 (Gingerbread) or later to use the Sinch SDK.

Production and Sandbox environments

Sinch provides two environments:

The environment is passed as the parameter environmentHost when instantiating the Sinch client.

Environment EnvironmentHost parameter

Restrictions on User IDs

User IDs can only contain characters in the printable ASCII character set. That is:


User IDs must not be longer than 40 characters.

Encryption export regulations and Google Play

Please check the Summary of U.S. Export Controls Applicable to Commercial Encryption Products and ensure that the application is registered for the Encryption Regulations, if applicable. It can be found under this link.


The Sinch SDK client uploads statistics to the Sinch servers at the end of a call, a call failure, or similar event. The statistics are used for monitoring of network status, call quality, and other aspects regarding the general quality of the service.

Some of the information is not anonymous and may be associated with the User ID call participants.

The statistics upload is done by the client in the background.

Push Notifications sent via your application server

In general we strongly recommend using “managed push notifications”, that is, when push notifications are sent directly from the Sinch cloud, which is described in the section Push notifications. The following section on the describes integrating support for push notifications but given that your application server maintain the connection with Firebase Cloud Messaging (former Google Cloud Messaging).

An application is considered offline in the following scenarios:

For these two scenarios, push notifications must be implemented in the application to be able to receive incoming calls. The following sections cover how to support receiving calls and messages via push notifications.

The Sinch client relies on a push service to launch the application if it is not currently listening for incoming calls due to the application being offline. Which push service to use is up to the developer, but for Android applications, the typical choice is to use Firebase Cloud Messaging (FCM). The examples that follow assume that Firebase Cloud Messaging is used to deliver push messages.

When offline, the recipient of a call or message receives a push notification containing a Sinch-specific payload that enables the Sinch Client to connect the incoming call or message. Acting on the push notification brings the application to the foreground allowing the user to answer the call or view the message.

Figure 2. Push notification sequence.
Figure 2. Push notification sequence.

Figure 2 describes the following sequence of events: Both users start their applications and Sinch clients. When A (the caller) calls B (the callee), B’s application is in a state where it is not considered online (that is reachable using an active socket connection). Sinch notices that B is not online, and tells A to send a push notification to B so that B can answer the call.

When the Sinch client on the caller’s (or sender’s) side observes that the destination client is offline, it notifies the application that it needs to trigger the sending of a push notification to the recipient device.

Push notification data

On startup, each instance of the application is expected to register a device identifier. The identifier is referred to as push notification data and should be provided to the Sinch client using the method registerPushNotificationData.

Push notifications can be addressed to that identifier in the event that the application goes offline.

The push notification data can be any byte sequence; it is up to you to define its structure and what it contains. However, the push notification data must not exceed 1024 bytes. It should contain enough information to allow a push service to send a push notification to a particular user of the application on a particular device. For example, an Android exclusive application would likely use the FCM registration id as its push notification data.

Multi-platform applications may use a mix of different push services. For instance, in an application running on both iOS and Android, the platform identifier in the push notification data can be used by the push server to determine whether APNS or FCM should be used.

The device-specific push notification data should be registered on start up of the application, or as soon as it’s available. If user B then turns off the application, and user A calls B, user A’s application would get the callback CallListener.onShouldSendPushNotification. One of the parameters in this callback, is a list of PushPairs that contain a payload and a push notification data. Each element in this list corresponds to each of B’s registered push notification data identifiers (a user can have multiple devices).

The push notification data can also be unregistered by calling the SinchClient.unregisterPushNotificationData method. This effectively disables incoming calls or messages using push notifications for the particular device.

Enable push notifications

The following sections assumes that FCM is used, but the use pattern for other push services is similar.

The easiest way to enable offline calls or messages using FCM is to first call SinchClient.setSupportPushNotifications(true) and then register the device specific push notification data with SinchClient.registerPushNotificationData. In a simple example we can use the registration id received from Google when registering to FCM.

// Register with the FCM service to get a device specific registrationId
// Should be done in a background job
String regId = FirebaseInstanceId.getInstance().getToken("Your-Sender-ID", "FCM");



Please refer to Google’s Firebase Cloud Messaging for Android for more information on how to use the FCM service.

Note: As described in the Push Data Notification section, the data that you register with the registerPushNotificationData method is defined by you. If using FCM, it must at a minimum include the registrationId from Google (so a FCM server can push to a particular device).

Send and receive push notifications

To send push messages the application developer must have a server that is configured for sending push notifications to the Firebase Cloud Messaging Service. Please see the Sinch REST API User Guide for details on how to handle feedback from Firebase Cloud Messaging Service.

Also refer to Google’s Firebase Cloud Messaging for Android for detailed information on how FCM works.

On the caller side

When the recipient’s application is offline and the app needs to notify the user using a push notification, the caller’s or sender’s application is notified using the callback method CallListener.onShouldSendPushNotification.

The callback includes a List of PushPairs. The pairs contain a payload that is Sinch- and call-specific. Moreover the pairs contain a push data byte array. The Sinch specific payload should be embedded in the push notification sent to the recipient’s device(s). The push data is the same push data that the recipient’s application registered earlier. There might be multiple registered devices for the recipient user (for example, the same user is using the application on both a phone and a tablet), which is why the callback includes a List of Push Pairs.

public void onShouldSendPushNotification(Call call, List<PushPair> pushPairs) {
    // Send payload and push data to application server
    // which should communicate with FCM Service to send push notifications.

A push notification should be sent to each device, where each entry in the parameter pushPairs list corresponds to one device. Each push notification should include the Sinch-specific payload so it can be forwarded to the Sinch client running on the destination device.

The Sinch-specific payload should be embedded as custom payload data in the FCM Payload.

  "registration_ids" : ["APA91bHun4MxP5egoKMwt2KZFBaFUH-1RYqx...", ...],
  "data" : {
    "Sinch" : <payload>,

Please refer to Google’s Firebase Cloud Messaging for Android for more information.

On the callee side

As a prerequisite, offline calling and messaging must be enabled on the receiver’s side (see Push Notifications sent via your application server).

When the application receives a push notification from the Firebase Cloud Messaging Service, the application should extract the Sinch-specific payload from the push notification, and forwarding it to the Sinch client using the method relayRemotePushNotificationPayload.

protected void onMessage(final Context context, final Intent intent) {
    String sinchPayload = intent.getStringExtra("Sinch");



This glossary defines some of the domain specific terms used throughout this document.

Term Explanation
Application The mobile application running on iOS and/or Android. A partner can have more than one application.
Application Instance One installation of the application on a single device.
Application Key A key generated by Sinch. The key is unique to the application. A key looks like 196087a1-e815-4bc4-8984-60d8d8a43f1d (lowercase hexadecimal formatted GUID).
Application Secret A string generated by Sinch. The secret is used to verify the application. A secret looks like oYdgGRXoxEuJhGDY2KQ/HQ== (Base64-encoded string representation).
Callee The person receiving a call.
Caller The person making a call.
User A user of the mobile application. The actual person holding the mobile device.
User Identity Identity of a user in the application domain. Can be any string, for instance a user name, user id, phone number or email address.
Active Connection A socket connection for signaling purposes where incoming calls are received.

Third party libraries and copyright notices

All Third Party Libraries and Copyright notices can be found under this link.