Signed Call™ React Native for M2P Campaigns

Learn how to integrate Signed Call™ React Native SDK in your application to avail the Signed Call Machine-to-Person (M2P) feature.

Overview

CleverTap supports Machine-to-Person (M2P) In-App campaign calls through its Signed Call™ React Native SDK. This allows you to receive and handle real-time M2P campaign calls in any React Native application if the device has an internet connection and the Signed Call React Native SDK.

This document provides information about:

  • Signed Call React Native SDK integration
  • Managing Signed Calls from your React Native application

For more information about the feature, refer to Signed Call for M2P Calls.

Prerequisites

The prerequisites for the integration vary depending on the platforms:

For Android Platform

Here are the requirements for integrating the Signed Call React Native SDK into the Android platform:

  • SDK version 21 and above
  • Java version 11 and above
  • Application permissions for the following:

📘

iOS Platform

CleverTap will soon start iOS Platform Support for M2P campaigns.

Integrate Signed Call React Native SDK

To integrate the Signed Call React Native SDK, perform the following four major steps:

  1. Add CleverTap React Native Package to Project.
  2. Set Up Signed Call Native SDKs.
  3. Initialize Signed Call React Native SDK.
  4. Manage Permissions.
  5. Receive M2P Campaign Calls.

Add CleverTap React Native Package to Project

To integrate the Signed Call React Native SDK, add the CleverTap React Native SDK/Package to your project using Yarn or NPM as shown below:

yarn add @clevertap/[email protected]
npm install @clevertap/[email protected]

Set Up Signed Call React Native SDKs

To set up the Signed Call Android SDK, perform the following steps:

  1. Include mavenCentral in your project-level build.gradle file as follows:
allprojects {
    repositories {
        mavenCentral()
    }
}
  1. Add the following code to the dependencies element of the build.gradle file of your application module:
//To integrate Signed Call Android SDK,
implementation "com.clevertap.android:clevertap-signedcall-sdk:0.0.7.1-m2p-beta"

//To enable the socket-based signaling channel
implementation('io.socket:socket.io-client:2.1.0') {
        exclude group: 'org.json', module: 'json'
} 

//To load the image assets on the call screens
implementation 'com.github.bumptech.glide:glide:4.12.0'

//To process the incoming call push for the receiver
implementation 'androidx.work:work-runtime:2.7.1'

//To build a responsive UI for the call screens
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'

The Signed Call Android SDK uses CleverTap Android SDK for analytics. This requires an active CleverTap instance as a parameter during the SDK initialization. To integrate the CleverTap Android SDK, refer to CleverTap Android SDK Integration.

📘

Signed Call React Native SDK Compatibility

The Signed Call React Native SDK v0.0.7-m2p.0 is compatible with Signed Call Android SDK v0.0.7.1-m2p-beta or higher and CleverTap Android SDK v7.3.1 or higher.

The Signed Call Android SDK uses the FCM dependency to fetch the device FCM token required for successful SDK initialization. It then uses this FCM token to enable calls via the FCM-based call routing channel.

  1. Add the following code to include the FCM dependency in the application module's dependency element:
implementation 'com.google.firebase:firebase-messaging:21.0.0'

📘

FCM Version

The minimum supported version of FCM must be v21.0.0 or higher to integrate with your Android platform.

Initialize Signed Call React Native SDK

To initialize the Signed Call React Native SDK in your JavaScript or TypeScript code, call the init method on the SignedCall reference as shown below:

static initialize(initProperties: object): Promise<SignedCallResponse>

This method returns a Promise object. To get the results, use the then() method as follows:

import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

SignedCall.initialize(initProperties)
  .then((response: SignedCallResponse) => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      const error = response.error;
      const errorCode = error?.errorCode;
      const errorMessage = error?.errorMessage;
      const errorDescription = error?.errorDescription;
      console.log(
            'Signed Call initialization failed: \n' +
            'error-code: ' + errorCode + '\n' +
            'error-message: ' + errorMessage + '\n' +
            'error-description: ' + errorDescription
      );
    }
  })
  .catch((e: any) => {
    console.error(e);
  });
import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

SignedCall.initialize(initProperties)
  .then(response => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      const error = response.error;
      const errorCode = error?.errorCode;
      const errorMessage = error?.errorMessage;
      const errorDescription = error?.errorDescription;
      console.log(
            'Signed Call initialization failed: \n' +
            'error-code: ' + errorCode + '\n' +
            'error-message: ' + errorMessage + '\n' +
            'error-description: ' + errorDescription
      );
    }
  })
  .catch(e => {
    console.error(e);
  });

The initProperties is a Map object with the following properties:

PropertiesDescriptionTypeComments
accountIdThe unique identity of the client account. It is available from the CleverTap dashboard.StringRequired
apiKeyThe unique identity of the client's account. It is available from the CleverTap dashboard.StringRequired
cuidThe unique identity of the user.StringRequired
m2pConfigurationIt configures the content of the foreground notification, which SDK uses to preprocess the received campaign calls.

For more information, refer to Configure Machine-to-Person (M2P) Feature.
ObjectRequired
missedCallActions
  • It configures the action buttons for the missed call notification.
  • No action buttons are displayed on a missed call notification without this parameter.
  • A maximum of three action buttons can be configured for the missed call notification, where each entry in the map object represents an action button.
For more information, refer to missedCallActions.
ObjectOptional
promptReceiverReadPhoneStatePermissionWhen the receiver answers the call, it prompts the receiver with Read Phone State permission.
The SDK uses Read Phone State permission to enable busy handling for PSTN calls. The default value is false.

For more information, refer to Read Phone State Permission.
BooleanOptional
promptPushPrimerIt enables the Push Primer to support Android 13 changes for the Runtime Notification Permission.

For more information, refer to Notification Permission.
ObjectOptional
overrideDefaultBrandingIt overrides the call screen branding set from the dashboard. The default branding is the one you set from the dashboard.

For more, refer to its usage.
ObjectOptional

📘

CUID Validation Rules

The following are the validation rules for cuid:

  • The characters must range between 5 to 50.
  • Start with either alphabet or a number.
  • The name is case-sensitive, and only '_' is allowed as a special character.
  • Cannot be of type number-number, i.e. a number followed by a special character, which is again followed by another number. For example, org_25 is allowed, but 91_8899555 is not permitted.
  • Must be unique for every user.
  • Must be unique for every device to allow multiple logins for the user from different devices. In such cases, the user will have multiple cuid's.

The syntax for initProperties is as follows:

import { Platform } from 'react-native';

let initProperties: { [k: string]: any } = {
      accountId: <string / required>,
      apiKey: <string / required>,
      cuid: <string / required>,
  		promptReceiverReadPhoneStatePermission: <boolean / optional>,
  		promptPushPrimer: <object / optional>,
  		overrideDefaultBranding: <object / optional>,
  		missedCallActions = <object / optional>,
}
import { Platform } from 'react-native';

let initProperties = {
      accountId: <string / required>,
      apiKey: <string / required>,
      cuid: <string / required>,
  		promptReceiverReadPhoneStatePermission: <boolean / optional>,
  		promptPushPrimer: <object / optional>,
  		overrideDefaultBranding: <object / optional>,
  		missedCallActions = <object / optional>,
}

Configure Machine-to-Person (M2P) Feature

The Signed Call React Native SDK runs a foreground service on the Android platform to communicate with the server before the actual campaign call and fetch information about the campaign meta and flow. During this process, the SDK displays a foreground notification to the user. After processing, the SDK replaces the foreground notification with the incoming call notification.

📘

Note

The foreground service keeps the application in the wake state, reducing the chances of communication failures due to network or device restrictions imposed by the Android OS or OEM.

To configure the foreground notification, use the m2pConfiguration parameter of the object type inside the initProperties as follows.

import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

let m2pConfiguration = {
  title: '<title>',    // Required
  subTitle: '<subTitle>',  // Required
  cancelCtaLabel: '<cancelCtaLabel>',  // Optional
  largeIcon: '<resource_name_in_android_drawable_folder>",   // Optional
};

let initProperties = {
  ....
  m2pConfiguration: m2pConfiguration,
  ....
};

SignedCall.initialize(initProperties)
  .then((response: SignedCallResponse) => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
 })
  .catch((e: any) => {
    console.error(e);
  });
import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

let m2pConfiguration = {
  title: '<title>',    // Required
  subTitle: '<subTitle>',  // Required
  cancelCtaLabel: '<cancelCtaLabel>',  // Optional
  largeIcon: '<resource_name_in_android_drawable_folder>",   // Optional
};

let initProperties = {
  ....
  m2pConfiguration: m2pConfiguration,
  ....
};

SignedCall.initialize(initProperties)
  .then(response => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
  })
  .catch(e => {
    console.error(e);
  });

The following table provides information about the parameters used in the m2pConfiguration object:

Method NameDescriptionTypeRequired/Optional
titleDenotes the title text. The maximum character limit is 65 characters.StringRequired
subtitleDenotes the subtitle text. The maximum character limit is 240 characters.StringRequired
largeIconDenotes the name of the drawable resource under android/app/src/res/drawable folder.StringOptional
cancelCtaLabelServes as an alternative for manual dismissal of the notification, ensuring users have an option if it does not disappear automatically.StringOptional

overrideDefaultBranding

CleverTap dashboard provides a branding tool to alter the look and feel of the call screens. If you have multiple applications to integrate with the Signed Call SDK, all those applications will share the same branding you have set from the CleverTap dashboard. By overriding the dashboard's call screen branding, you can have different branding for each application.

Use an optional overrideDefaultBranding parameter of the object type inside the initProperties to override the dashboard branding for call screens.

import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

let callScreenBranding = {
  bgColor: '<hex color code>',    //The background color of the call screens
  fontColor: '<hex color code>',  //The color of the text displayed on the call screens
  logoUrl: '<https url>',         //The image URL that renders on the call screens.
  buttonTheme: 'light' or "dark", //The theme of the control buttons shown on the ongoing call screen(i.e. Mute, Speaker and Bluetooth)
};

let initProperties = {
  ....
  overrideDefaultBranding: callScreenBranding,
  ....
};

SignedCall.initialize(initProperties)
  .then((response: SignedCallResponse) => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
 })
  .catch((e: any) => {
    console.error(e);
  });
import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

let callScreenBranding = {
  bgColor: '<hex color code>',    //The background color of the call screens
  fontColor: '<hex color code>',  //The color of the text displayed on the call screens
  logoUrl: '<https url>',         //The image URL that renders on the call screens.
  buttonTheme: 'light' or "dark", //The theme of the control buttons shown on the ongoing call screen(i.e. Mute, Speaker and Bluetooth)
};

let initProperties = {
  ....
  overrideDefaultBranding: callScreenBranding,
  ....
};

SignedCall.initialize(initProperties)
  .then(response => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
  })
  .catch(e => {
    console.error(e);
  });

Manage Permissions

Signed Call Android SDK uses and manages the following permissions for M2P Campaigns:

Notification Permission

This is a required permission. All applications running on Android 13 and above must request Runtime Notification Permission from the user before using notifications.

For the Android platform, the Signed Call React Native SDK utilizes both local and remote notifications during M2P campaigns. Therefore, notification permission must be granted by the user before initializing the SDK. To manage notification permissions in your app, refer to the Push Primer for Notification Permission.

Read Phone State Permission

This is an optional permission. The Signed Call React Native SDK uses this permission to enable busy handling for Public Switched Telephone Network (PSTN) calls. This permission determines if the receiver is available or engaged on a PSTN call. CleverTap recommends you add the required handling to request the Read Phone State permission.

Use the promptReceiverReadPhoneStatePermission parameter of the boolean type inside the initProperties as shown below, allow the Signed Call React Native SDK to prompt the read phone state permission at the receiver's end when the receiver answers the call.

import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

let initProperties = {
  ....
  promptReceiverReadPhoneStatePermission: true/false,
  ....
};

SignedCall.initialize(initProperties)
  .then((response: SignedCallResponse) => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
  })
  .catch((e: any) => {
    console.error(e);
  })
import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

let initProperties = {
  ....
  promptReceiverReadPhoneStatePermission: true/false,
  ....
};

SignedCall.initialize(initProperties)
  .then(response => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
  })
  .catch(e => {
    console.error(e);
  });

📘

Note

When the Read Phone State permission is enabled, the SDK detects if the recipient is currently on another call. If they are, the campaign call is automatically declined, and the recipient is marked as busy.
If this permission is disabled, the campaign call enters a waiting state. In this case, the recipient still receives a campaign notification and can choose whether to end their current call and accept the campaign call.

Full-Screen Intent Permission

The Signed Call React Native SDK uses the Full-Screen Intent permission on Android to display full-screen notifications for incoming VoIP calls when the app is not running in the foreground. This ensures a user experience similar to other VoIP-capable apps. For more information on how to declare and manage this permission in the Google Play Console, refer to Full-Screen Intent Permission in Android 14.

DataSync Permission

The Signed Call React Native SDK uses the FOREGROUND_SERVICE_DATA_SYNC permission on Android to handle the received M2P campaigns by preprocessing it by running a foreground service as mentioned in the Configure Machine-to-Person (M2P) Feature section. For more information on how to declare and manage this permission in the Google Play Console, refer to Google Play Console Declaration section.

Bluetooth Connect Permission

This is an optional permission, but it is recommended for a better user experience. The Signed Call React Native SDK has built-in Bluetooth management support. However, enabling this feature on Android 12 and onwards requires Bluetooth Connect permission.

The Signed Call React Native SDK uses this permission to enable communication with the paired Bluetooth device for audio management on Android 12 and onwards. To optimize the call experience, we recommend you request Bluetooth Connect permission.

Receive a Machine-to-Person (M2P) Campaign Call

Signed Call uses the FCM routing channel to receive M2P campaign calls at the receiver's end:

📘

FCM Version

The minimum supported version of FCM must be v21.0.0 or higher to integrate with your Android platform.

To enable the FCM channel, follow these steps:

  1. Add your FCM Server Key to the Signed Call section of the CleverTap dashboard. Ignore this step if you have already added it.
  2. Allow CleverTap Android SDK to process the FCM push of VoIP call by adding the following entries to your AndroidManifest.xml file.
<application>
         ....
         ....
        <service android:name="com.clevertap.android.sdk.pushnotification.fcm.FcmMessageListenerService"
                 android:exported="true">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
        ....  
 </application>

  1. Add the following code to your Application class:
CleverTapAPI.setSignedCallNotificationHandler(new SignedCallNotificationHandler());
CleverTapAPI.setSignedCallNotificationHandler(SignedCallNotificationHandler())

The setup for campaign calls via the FCM channel is now complete.

Push Primer for Notification Permission

The Push Primer is a local In-App notification that educates users about the context of the notification before requesting permission.

To initialize the Signed Call React Native SDK for Android 13 and above, you can enable the Push Primer using any of the following:

Enable Push Primer via CleverTap React Native SDK

To integrate notification permission management, refer to CleverTap React Native Push Primer.

Enable Push Primer via Signed Call React Native SDK

The Signed Call React Native SDK enables you to display Push Primer using an optional promptPushPrimer parameter of Object type inside the initProperties. It ensures that the initialization happens after the notification permission is granted using Push Primer.

To configure the Push Primer, perform the following steps:

  1. Create a Push Primer configuration using the In-App campaign's Half-Interstitial or Alert template.
//Creates push primer config using Half-Interstitial template
const pushPrimerConfig = {
  inAppType: 'half-interstitial',
  titleText: 'Get Notified',
  messageText:'Please enable notifications on your device to use Push Notifications.',
  followDeviceOrientation: true,
  positiveBtnText: 'Allow',
  negativeBtnText: 'Cancel',
  backgroundColor: '#FFFFFF',
  btnBorderColor: '#0000FF',
  titleTextColor: '#0000FF',
  messageTextColor: '#000000',
  btnTextColor: '#FFFFFF',
  btnBackgroundColor: '#0000FF',
  btnBorderRadius: '2',
  fallbackToSettings: true, //Setting this parameter to true will open an in-App to redirect you to Mobile's OS settings page.
};

//Creates push primer config using Alert template
const pushPrimerConfig = {
  inAppType: 'alert',
  titleText: 'Get Notified',
  messageText: 'Enable Notification permission',
  followDeviceOrientation: true,
  positiveBtnText: 'Allow',
  negativeBtnText: 'Cancel',
  fallbackToSettings: true, //Setting this parameter to true will open an in-App to redirect you to Mobile's OS settings page.
};
//Creates push primer config using Half-Interstitial template
const pushPrimerConfig = {
  inAppType: 'half-interstitial',
  titleText: 'Get Notified',
  messageText:'Please enable notifications on your device to use Push Notifications.',
  followDeviceOrientation: true,
  positiveBtnText: 'Allow',
  negativeBtnText: 'Cancel',
  backgroundColor: '#FFFFFF',
  btnBorderColor: '#0000FF',
  titleTextColor: '#0000FF',
  messageTextColor: '#000000',
  btnTextColor: '#FFFFFF',
  btnBackgroundColor: '#0000FF',
  btnBorderRadius: '2',
  fallbackToSettings: true, //Setting this parameter to true will open an in-App to redirect you to Mobile's OS settings page.
};

//Creates push primer config using Alert template
const pushPrimerConfig = {
  inAppType: 'alert',
  titleText: 'Get Notified',
  messageText: 'Enable Notification permission',
  followDeviceOrientation: true,
  positiveBtnText: 'Allow',
  negativeBtnText: 'Cancel',
  fallbackToSettings: true, //Setting this parameter to true will open an in-App to redirect you to Mobile's OS settings page.
};
  1. Pass the Push Primer configuration inside the promptPushPrimer parameter of the initProperties. It displays the Push Primer during the SDK initialization.
import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

let initProperties = {
  ....
  promptPushPrimer: pushPrimerConfig,
  ....
};

SignedCall.initialize(initProperties)
  .then((response: SignedCallResponse) => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
  })
  .catch((e: any) => {
    console.error(e);
  });
import {
  SignedCall,
  SignedCallResponse,
} from '@clevertap/clevertap-signed-call-react-native';

let initProperties = {
  ....
  promptPushPrimer: pushPrimerConfig,
  ....
};

SignedCall.initialize(initProperties)
  .then(response => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
  })
  .catch(e => {
    console.error(e);
  });

📘

Note

  • The above configuration enables the Push Primer only if the device and application both target Android 13 (API level 33) or higher.
  • During the SDK initialization, Signed Call React Native SDK registers a listener to obtain the result of the push notification permission request. After registration, this listener continues monitoring the permission result, even if the Push Primer prompt is displayed from the CleverTap React Native SDK.
  • If the notification permission is denied, the Signed Call React Native SDK returns an exception within the promise object that is associated to the SignedCall.initialize(..) method.

Handle Call Events

To define custom handling for call-related events, you must register the SignedCall.SignedCallOnCallStatusChanged listener. This listener provides an object - CallStatusDetails containing information about the call.

To define custom handling for distinct call events, refer to the code below:

import {
  SignedCall,
  CallDirection,
  CallStatus,
  CallType,
  CallStatusDetails
} from '@clevertap/clevertap-signed-call-react-native';

//To start observing the changes in a call states.
SignedCall.addListener(
    SignedCall.SignedCallOnCallStatusChanged,
     (result: CallStatusDetails) => {    console.log('SignedCallOnCallStatusChanged', result);
    console.log(`${result.callStatus}, ${result.callOptions.campaignId}`);
    
    switch (result.callStatus) {    
    case CallStatus.CallIsPlaced:
      // Indicates that the call is successfully placed
      console.log('Call is successfully placed');
      break;
		
    case CallStatus.Declined:
      // Indicates that the call is declined from the receiver's end
      console.log('Call is declined from the receiver’s end');
      break;

    case CallStatus.Missed:
      // Indicates that the call is missed at the receiver's end
      console.log('Call is missed at the receiver’s end');
      break;

    case CallStatus.Answered:
      // Indicates that the call is picked up by the receiver
      console.log('Call is answered by the receiver');
      break;

    case CallStatus.CallInProgress:
      // Indicates that the connection to the receiver is established, and the audio transfer begins at this state
      console.log('Call is in progress');
      break;

    case CallStatus.CallOver:
      // Indicates that the call is over
      console.log('Call is over');
      const dtmfInputList = result.callOptions.dtmfInputList;
      if (dtmfInputList) {
        console.log(`Size of DTMF inputs list: ${dtmfInputList.length}`);
      }
      break;

    case CallStatus.CalleeBusyOnAnotherCall:
      // Indicates that the receiver is already busy on another call
      console.log('Receiver is busy on another call');
      break;

    case CallStatus.DeclinedDueToLoggedOutCuid:
      // Indicates that the call is declined due to the receiver being logged out with the specific CUID
      console.log('Call is declined due to logged-out CUID');
      break;

    case CallStatus.DeclinedDueToNotificationsDisabled:
      // Indicates that the call is declined due to notifications being disabled at the receiver's end
      console.log('Call is declined due to notifications being disabled');
      break;

    case CallStatus.CallCancelledDueToTtlExpired:
      // Indicates that the campaign call is cancelled due to TTL being expired
      console.log('Call is cancelled due to TTL expired');
      break;

    case CallStatus.CallCancelledDueToCampaignNotificationCancelled:
      // Indicates that the M2P call is cancelled by clicking on cancel CTA from campaign's pre-processing notification
      console.log(
        'Call is cancelled by clicking on cancel CTA from campaign’s notification'
      );
      break;

    case CallStatus.DTMFInputReceived:
      // Indicates that a DTMF input is received from M2P keypad screen
      console.log('DTMF input is received from M2P keypad screen');
      const dtmfInput = result.callOptions.getDtmfInput();
      if (dtmfInput) {
        console.log(`${dtmfInput.inputKey} is pressed!`);
      }
      break;

    default:
      // Handle any unexpected or unhandled statuses
      console.log('Unhandled call status:', result.callStatus);
      break;
  }
});

// To stop observing the changes in a call state.
SignedCall.removeListener(SignedCall.SignedCallOnCallStatusChanged);
import {
  SignedCall,
  CallDirection,
  CallStatus,
  CallType,
  CallStatusDetails
} from '@clevertap/clevertap-signed-call-react-native';

// To start observing the changes in call states.
SignedCall.addListener(SignedCall.SignedCallOnCallStatusChanged, (result) => {
  console.log('SignedCallOnCallStatusChanged', result);
  console.log(`${result.callStatus}, ${result.callOptions.campaignId}`);
  
  switch (result.callStatus) {
    case CallStatus.CallIsPlaced:
      // Indicates that the call is successfully placed
      console.log('Call is successfully placed');
      break;

    case CallStatus.Declined:
      // Indicates that the call is declined from the receiver's end
      console.log('Call is declined from the receiver’s end');
      break;

    case CallStatus.Missed:
      // Indicates that the call is missed at the receiver's end
      console.log('Call is missed at the receiver’s end');
      break;

    case CallStatus.Answered:
      // Indicates that the call is picked up by the receiver
      console.log('Call is answered by the receiver');
      break;

    case CallStatus.CallInProgress:
      // Indicates that the connection to the receiver is established, and the audio transfer begins at this state
      console.log('Call is in progress');
      break;

    case CallStatus.CallOver:
      // Indicates that the call is over
      console.log('Call is over');
      const dtmfInputList = result.callOptions.dtmfInputList;
      if (dtmfInputList) {
        console.log(`Size of DTMF inputs list: ${dtmfInputList.length}`);
      }
      break;

    case CallStatus.CalleeBusyOnAnotherCall:
      // Indicates that the receiver is already busy on another call
      console.log('Receiver is busy on another call');
      break;

    case CallStatus.DeclinedDueToLoggedOutCuid:
      // Indicates that the call is declined due to the receiver being logged out with the specific CUID
      console.log('Call is declined due to logged-out CUID');
      break;

    case CallStatus.DeclinedDueToNotificationsDisabled:
      // Indicates that the call is declined due to notifications being disabled at the receiver's end
      console.log('Call is declined due to notifications being disabled');
      break;

    case CallStatus.CallCancelledDueToTtlExpired:
      // Indicates that the campaign call is cancelled due to TTL being expired
      console.log('Call is cancelled due to TTL expired');
      break;

    case CallStatus.CallCancelledDueToCampaignNotificationCancelled:
      // Indicates that the M2P call is cancelled by clicking on cancel CTA from campaign's pre-processing notification
      console.log(
        'Call is cancelled by clicking on cancel CTA from campaign’s notification'
      );
      break;

    case CallStatus.DTMFInputReceived:
      // Indicates that a DTMF input is received from M2P keypad screen
      console.log('DTMF input is received from M2P keypad screen');
      const dtmfInput = result.callOptions.getDtmfInput();
      if (dtmfInput) {
        console.log(`${dtmfInput.inputKey} is pressed!`);
      }
      break;

    default:
      // Handle any unexpected or unhandled statuses
      console.log('Unhandled call status:', result.callStatus);
      break;
  }
});

// To stop observing the changes in a call state.
SignedCall.removeListener(SignedCall.SignedCallOnCallStatusChanged);

Handle Call Events in Killed State

📘

Default Listener Behavior

The SignedCall.SignedCallOnCallStatusChanged listener receives updates only when the app is open or running in the background, not when it is in killed state.

To enable the SignedCall.SignedCallOnCallStatusChanged listener in the killed state, follow these two steps:

  1. Add the following code to the onCreate() method of your Application class:
SignedCallOnCallStatusListener.register(this);
SignedCallOnCallStatusListener.register(this)
  1. Register the SignedCall.SignedCallOnCallStatusChanged listener in the index.js file. It is the entry point of the React Native application. For a sample implementation, refer to index.js file of the Signed Call React Native Example Project.

The setup is now complete to receive call events in the killed state.

Handle Missed Call

If the receiver misses a call, the Signed Call React Native SDK shows a missed call notification to the receiver. The Signed Call React Native SDK uses action buttons on the missed call notification to display a Call to Action (CTA).

To configure the CTA on the missed call notification, add the following code:

  1. Create a Map object for missedCallActions parameter with a maximum of three entries.
let missedCallActionsMap = {
      '<Unique Identifier 1>': '<label on action-button 1>',
      '<Unique Identifier 2>': '<label on action-button 2>',
      '<Unique Identifier 3>': '<label on action-button 3>',
};
 
let initProperties = {
  ....
  missedCallActions: missedCallActionsMap,
  ....
};

SignedCall.initialize(initProperties)
  .then((response: SignedCallResponse) => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
  })
  .catch((e: any) => {
    console.error(e);
  });
let missedCallActionsMap = {
      '<Unique Identifier 1>': '<label on action-button 1>',
      '<Unique Identifier 2>': '<label on action-button 2>',
      '<Unique Identifier 3>': '<label on action-button 3>',
};
 
let initProperties = {
  ....
  missedCallActions: missedCallActionsMap,
  ....
};

SignedCall.initialize(initProperties)
  .then(response => {
    if (response.isSuccessful) {
      console.log('Signed Call SDK initialized: ', response);
    } else {
      console.log('Signed Call initialization failed: ', response.error);
    }
  })
  .catch(e => {
    console.error(e);
  });
  1. Insert the following code to subscribe to the MissedCallActionClickResult event stream, allowing you to listen for CTA click events on missed call notifications:
import {
  SignedCall,
  MissedCallActionClickResult,
} from '@clevertap/clevertap-signed-call-react-native';

SignedCall.addListener(
      SignedCall.SignedCallOnMissedCallActionClicked,
      (event: MissedCallActionClickResult) => {
        console.log('SignedCallOnMissedCallActionClicked', event);
        Alert.alert(
          'Missed Call Notification!',
          event.action.actionLabel + ' is clicked'
        );
      }
    );
import {
  SignedCall,
  MissedCallActionClickResult,
} from '@clevertap/clevertap-signed-call-react-native';

//To start observing the CTA click on a missed call notification.
SignedCall.addListener(
      SignedCall.SignedCallOnMissedCallActionClicked,
      event => {
        console.log('SignedCallOnMissedCallActionClicked', event);
      }
    );

//To stop observing the CTA click on a missed call notification.
SignedCall.removeListener(SignedCall.SignedCallOnMissedCallActionClicked);

📘

Killed State Support for SignedCall.SignedCallOnMissedCallActionClicked

To enable the SignedCall.SignedCallOnMissedCallActionClicked listener in killed state, register the SignedCall.SignedCallOnMissedCallActionClicked listener in the index.js file, the entry point of the React Native application. For a sample implementation, refer to index.js file of the Signed Call React Native Example Project.

Log Out Signed Call React Native SDK

When the Signed Call React Native SDK initializes, the init configuration is maintained in a local session. Use the logout() method to invalidate the active session and disable the Signed Call functionality (receiving the M2P campaigns).

SignedCall.logout();
SignedCall.logout();

Debugging

Signed Call React Native SDK logs are, by default, set to the LogLevel.info level. CleverTap recommends you set the log level to LogLevel.verbose mode to log warnings or other important messages during development. If you want to disable the Signed Call React Native SDK logs for the production environment, you can set the debug level to LogLevel.off.

SignedCall.setDebugLevel(LogLevel.info); //default level, shows minimal SDK integration related logging

SignedCall.setDebugLevel(LogLevel.debug); //shows debug output

SignedCall.setDebugLevel(LogLevel.verbose); //shows verbose output

SignedCall.setDebugLevel(LogLevel.off);  //disables all debugging
SignedCall.setDebugLevel(LogLevel.info); //default level, shows minimal SDK integration related logging

SignedCall.setDebugLevel(LogLevel.debug); //shows debug output

SignedCall.setDebugLevel(LogLevel.verbose); //shows verbose output

SignedCall.setDebugLevel(LogLevel.off);  //disables all debugging

The log window displays the logs from the Signed Call SDKs. After setting the debug level, search for the following tags:

PlatformTAG
Android[CT]:[SignedCall]
React Native[CT]:[SignedCall]:[RN]

Sample Project: Implementing Signed Call React Native SDK

For example, for a project integrating the Signed Call React Native SDK in your React Native application, refer to Signed Call React Native Example Project.

📘

Note

Ensure you have added valid Signed Call and CleverTap Account credentials for the calling to work.

Error Handling

The Signed Call React Native SDK provides error reporting and handling.

The SignedCall.initialize(..) method is associated with promise objects that receive a SignedCallResponse object. This object contains any initialization that may occur.

The following is the list of initialization errors:

Error CodeDescription
1000No internet connection.
2000The application context is missing.
2001The CleverTapApi instance is missing.
2002The initProperties is missing.
2003The Signed Call Android SDK is not initialized.
2004The accountId and apiKey parameters are missing.
2005The cuid is missing.
2006The cuid length is invalid.
2007Invalid cuid due to violation of valid cuid rules.
2008The length of the name parameter is invalid.
2009The appId is invalid.
2010The branding configuration is invalid.
2011The values in initProperties are invalid.
2012The user authentication is not successful.
2013The notification permission was not given during the SDK initialization.
2014FCM token is missing. Please try again.

FAQs

Is Signed Call accountId and apiKey the same as CleverTap accountId and token?

No. Signed Call accountId and apiKey differ from CleverTap's accountId and token. You can find these details under your dashboard's Signed Call Settings.

Does the Signed Call React Native SDK support In-App calls over Bluetooth?

Yes. The Signed Call React Native SDK has built-in Bluetooth support. However, it requires a runtime BLUETOOTH_CONNECT permission for Android 12 and onwards.