react-native-incode-sdk Usage guide

Installation

To get standard version of the React Native Incode SDK run this command:

npm i @incode-sdks/react-native-incode-sdk

or specify it directly in package.json:

"@incode-sdks/react-native-incode-sdk": "9.0.0"

Additional SDK variants include:

  • End-to-End Encryption (9.0.0-e2ee)
  • Streaming (9.0.0-vc)

Example usage in package.json:

"@incode-sdks/react-native-incode-sdk": "9.0.0-e2ee"

Additional setup for iOS

After installation, it's necessary to do the linking for the iOS, after running the command above.
Requirements:

  • Xcode 15.0.1+
  • Swift 5.5+
  • Cocapods 1.11+
  • iOS 13+
  1. Change your Podfile so it equires deployment target 13 or higher.
-platform :ios, '10.0'
+platform :ios, '13.0'
  1. Add these lines to the top of your Podfile
    2.a Specify source of the iOS dependencies:
    + source 'https://cdn.cocoapods.org/'
    + source '[email protected]:Incode-Technologies-Example-Repos/IncdDistributionPodspecs.git'
    
    2.b If needed added path to the iOS dependencies location:
     RN >= 0.69
        no changes needed
     RN < 0.69
 pod 'react-native-incode-sdk', :path => '../node_modules/@incode-sdks/react-native-incode-sdk/'
  1. Add an empty Swift file (e.g. Void.swift) through xCode to your native project. When prompted for a bridging header, choose Create Bridging header.

  2. Relying on React Native's auto-linking, run the following:

cd ios && pod install cd ..
  1. Adapt Info.plist by adding:
  • NSCameraUsageDescription. The SDK uses the camera in order to verify the identity of the customer, e.g. in ID scan, Selfie scan and so on.
  • NSLocationWhenInUseUsageDescription. The SDK uses the current user location in order to detect exact location for Geolocation step.
  • NSMicrophoneUsageDescription. The SDK uses microphone for performing a video call during Video Conference step or for doing speech recognition during Video Selfie.
  1. Add Linker flags

Go to your projects Target, then Build Settings -> Other Linker Flags and add these flags:

$(inherited) -all_load -ObjC -l “stdc++” -l “iconv”

Additional setup for Android

In your app's build.gradle please make sure that following settings are set:

  1. Change your minSdkVersion to 21 or higher. Set compileSdkVersion to 34 or higher.

  2. Application has multidex support enabled:

  defaultConfig {
    ...
+   multiDexEnabled true
    ...
  }
  dependencies {
    ...
+   implementation 'com.android.support:multidex:1.0.3'
    ...
  }

Your Application class should now be able to extend MultiDexApplication:


+  import androidx.multidex.MultiDexApplication;

+  public class MyApplication extends MultiDexApplication implements ReactApplication {
  ...
 }
  1. Modify your project's build.gradle so it contains Artifactory username and password, provided by Incode.
allprojects {
  repositories {
    ...
+    maven { url "https://jitpack.io" }
+    maven {
+      url "https://repo.incode.com/artifactory/libs-incode-welcome"
+      credentials {
+        username = "ARTIFACTORY_USERNAME"
+        password = "ARTIFACTORY_PASSWORD"
+      }
+    }
    ...
  }
}

Installation Expo SDK

  1. Install SDK
npx expo install @incode-sdks/react-native-incode-sdk
  1. Install configuration plugin
npx expo install @incode-sdks/expo-incode-sdk-configuration
  1. Integrate and configure configuration plugin. Update 'plugins' field in app.json file:
{
  "expo": {
    "plugins": [
      [
        "@incode-sdks/expo-incode-sdk-configuration",
        {
          "artifactoryUserName": "client_artifactory_username",
          "artifactoryPassword": "client_artifactory_password",
          "addIncodeSourceToPodfile": true,
          "addStreaming": "X.Y.Z", // optional, add com.incode.sdk:video-streaming: $X.Y.Z dependency to android gradle file
          "addFaceMaskDetection": "X.Y.Z", // optional, com.incode.sdk:model-mask-detection:$X.Y.Z to android gradle file
          "addDynamicLocalization": "X.Y.Z" // optional, com.incode.sdk:extensions:X.Y.Z dependency to android gradle file
        }
      ]
    ]
  }
}

Usage

The typical basis workflow includes the following steps:

  1. Explicitly initialize IncodeSdk
  2. After waiting for the SDK to be initialized, configure Incode Onboarding Flow, by selecting modules (steps) you need
  3. Register listeners for steps-related events (e.g. step completion, step update, step failure)
  4. Run the Onboarding flow

Usage Example

import React from 'react';
import IncodeSdk from '@incode-sdks/react-native-incode-sdk';
import { View, TouchableOpacity } from 'react-native';

const StartOnboardingButton = () => {
  // 1. initialization
  const initializeAndRunOnboarding = () => {
    IncodeSdk.initialize({
      testMode: false,
      apiConfig: {
        key: 'YOUR API KEY HERE',
        url: 'YOUR API URL HERE',
      },
    })
      .then((_) => {
        // 2. configure and start onboarding
        startOnboarding();
      })
      .catch((error) => {
        const e = error as IncodeSdkInitError;
        console.error(`Incode SDK initialize failed with error ${e.code} - ${e.message}`);
      });
  };

  const startOnboarding = () =>
    IncodeSdk.startOnboarding({
      flowConfig: [
        { module: 'IdScan' },
        { module: 'SelfieScan' },
        { module: 'FaceMatch' },
      ],
    })
      .then((result) => {
        console.log(result);
      })
      .catch((error) => console.log(error));

  // 3: register listeners for relevant events when the component gets mounted
  React.useEffect(() => {
    const unsubscribers = setupListeners(); //defined below

    // return a function unregistering all your listeners (called when component is unmounted)
    return () => {
      unsubscribers.forEach((unsubscriber) => unsubscriber());
    };
  }, []);

  return <TouchableOpacity label="Start onboarding!" onPress={initializeAndRunOnboarding} />;
};

const setupListeners = () => {
  // returns a callback to unregister your listener, e.g. when your screen is getting unmounted
  IncodeSdk.onSessionCreated((session) => {
      console.log('Onboarding session created, interviewId: ' + session.interviewId);
    })

  const complete = IncodeSdk.onStepCompleted;
  return [
    complete({
      module: 'IdScanFront',
      listener: (e) => {
        console.log('ID scan front:', e.result);
      },
    }),
    complete({
      module: 'IdScanBack',
      listener: (e) => {
        console.log('ID scan back: ', e.result);
      },
    }),
    complete({
      module: 'ProcessId',
      listener: (e) => {
        console.log('ProcessId result: ', e.result.extendedOcrData);
      },
    }),
    complete({
      module: 'SelfieScan',
      listener: (e) => {
        console.log('Selfie scan complete', e.result);
      },
    }),

    complete({
      module: 'FaceMatch',
      listener: (e) => {
        console.log('Face match complete', e.result);
      },
    }),
  ];
};

Initialize the SDK

Parameters available for IncodeSDK.initialize method:

  • testMode - Set to true if running on simulator/emulators, false when running on devices. Default false.
  • sdkMode - Specify standard or captureOnly modes. Default is standard. captureOnly mode works completely offline and for ID and Selfie scan only does image captures without doing any validations.
  • disableHookCheck - Set to true if you would like to test the app on Android devices that have some hook frameworks installed, cause they are not allowed in production. Default false.
  • waitForTutorials - Specifying false means that the users can see and press continue button on all video tutorial screens without waiting for the video to complete. Default true.
  • apiConfig
    • key [optional] - API key, provided by Incode
    • url - API url, provided by Incode
    • e2eeUrl - custom server url used for End-to-End Encryption (E2EE)
  • sslPinningConfig
    • enabled - Set to false to disable SSL pinning. Default is true
  • disableJailbreakDetection - Set to true if you would like to disable jalibreak detection. Valid only for iOS. Default false.
  • externalAnalyticsEnabled - Set to true if you would like to enable external analytics. Default true.
  • loggingEnabled - Set to true if you would like to enable logging. Default true.
  • externalScreenshotsEnabled - Set to true if you would like to enable external screenshots. Default false.
  • disableEmulatorDetection - Set to true if you would like to disable emulator detection.Valid only for Android. Default false.
  • disableRootDetection - Set to true if you would like to disable root detection. Valid only for Android. Default false.

IncodeSDK.initialize method throws IncodeSdkInitError error with following possible values for field code:
simulatorDetected, testModeEnabled, invalidInitParams, configError, unknown

Start the onboarding

IncodeSdk.startOnboarding will create a new session based on specified list of modules that you provide via flowConfig.

To change session parameters, specify them inside optional sessionConfig parameter:

  • region - Specify a region, currently supported are ALL(covers all regions), BR (optimized for Brazil) and IN (optimized for India)
  • queue - Specify a queue to which this onboarding session will be attached to
  • interviewId - In case you're creating an onboarding session on the backend, you can provide its interviewId and the flow will be started for that particular onboarding session
  • configurationId - In case you've created a flow on the dashboard with a specific configuration, you can provide it here so that those settings apply to this session
  • token - In case you're creating an onboarding session on the backend, you can provide its token and the flow will be started for that particular onboarding session
  • externalId - ID used outside of Incode Omni
  • validationModules - List of validation modules that should be enabled in this session
  • customFields - Custom data that should be attached to this onboarding session
  • e2eEncryptionEnabled - Enable e2e encryption.

To enable screen recording of ID and Selfie capture, specify optional recordSessionConfig parameter:

  • Set recordSession to true
  • Set forcePermissions, true if you wish to abort the session in case user denies permissons, false otherwise

Start workflow

IncodeSdk.startWorkflow will create a new session based on configurationId that you provide via sessionConfig.

To change session parameters, specify them inside required sessionConfig parameter:

  • configurationId - Configuration ID of a flow on the dashboard. Required parameter.
  • region - Specify a region, currently supported are ALL(covers all regions), BR (optimized for Brazil) and IN (optimized for India)
  • queue - Specify a queue to which this onboarding session will be attached to
  • interviewId - In case you're creating an onboarding session on the backend, you can provide its interviewId and the flow will be started for that particular onboarding session
  • token - In case you're creating an onboarding session on the backend, you can provide its token and the flow will be started for that particular onboarding session
  • externalId - ID used outside of Incode Omni
  • validationModules - List of validation modules that should be enabled in this session
  • customFields - Custom data that should be attached to this onboarding session

To enable screen recording of ID and Selfie capture, specify optional recordSessionConfig parameter:

  • Set recordSession to true
  • Set forcePermissions, true if you wish to abort the session in case user denies permissons, false otherwise

Supported modules

The modules supported by the SDK are listed here, and elaborated in more detail throughout the rest of this document.

  • Phone
  • DocumentScan
  • Geolocation
  • UserConsent
  • Signature
  • VideoSelfie
    • ⚠️ Android note: Available only for API level 21+.
  • IdScan (does capture of both front and back ID and validates it)
  • IdScanFront (does capture of ony front)
  • IdScanBack (does capture of only back)
  • ProcessId (does only validation of the ID - should be called once IdScanFront and IdScanBack are completed)
  • Conference
  • SelfieScan
  • FaceMatch
  • QrScan
  • Email
  • Approve
  • UserScore
  • MLConsent
  • GovernmentValidation
  • Antifraud
  • GlobalWatchlist
  • CustomWatchlist
  • Aes
  • Name
  • CURP
  • OCREdit
  • eKYB
  • eKYC

Modules interdependencies

The order of the modules in the config array indicates the execution order.
Note that:

  • FaceMatch module expects IdScan and SelfieScan to have executed, in order to perform the match. In other words, IdScan and SelfieScan must precede FaceMatch
  • ProcessId module expects IdScanFront and IdScanBack to have executed, in order to validate the ID properly. In other words, IdScanFront and IdScanBack must precede ProcessId
  • UserScore module should succeed all other modules (must be at the end)
  • Approve module should succeed all other modules (must be at the end)
  • The UserScore and Approve modules do not depend on each other, so their order can be arbitrary.

Onboarding flow and workflow execution results

When the flow completes, the promise startOnboarding and startWorkflow will contain the execution status:

{ "status": "success" }

In case the user cancels the process, the status will be user_cancelled.

In case the execution can not be completed, promise will be rejected with a IncodeSdkFlowError with following possible values for field code:
simulatorDetected, rootDetected, hookDetected, badEnvDetected,virtualEnvDetected, permissionsDenied, unknown

Example of handling the error:

try {
      const onboardingResult = await IncodeSdk.startOnboarding({
        sessionConfig: sessionConfig,
        flowConfig: flowConfig,
      });
    } catch (error) {
      const e = error as IncodeSdkFlowError;
      if (e.code === 'permissionsDenied') {
        console.log(`User denied some mandatory permission during the flow`);
      } else {
        console.log('Unknown error occured')
      }
    }

Workflow execution results

When the workflow completes, the promise startWorkflow will contain the execution status:

{ "status": "success" }

In case the user cancels the process, the status will be user_cancelled.

In case the execution can not be completed, the startWorkflow promise will be rejected. This can happen:

  • if the user cancels the process
  • if the user fails to enter the correct captcha for 3 times (given the Captcha module is included)

Modules configuration

Common configuration needed for each module includes:

Parameter nameFunction
moduleNameMandatory. The name of the module we wish to include
enabledOptional: Whether or not the module is needed in the flow

Below is the list of all available module names, with additional configuration parameters.

  • Phone

    • otpVerification (optional, defaults to false): Ask for otp verification
  • DocumentScan

    • showTutorial (optional, defaults to false): Show tutorial for document scan.
    • showDocumentProviderScreen (optional, defaults to true): Specify true if you would like to show document provider screen to the user, or false if you would like to go directly to the capture.
    • type - specify document type addressStatement, paymentProof, medicalDoc, otherDocument1, otherDocument2, otherDocument3.
  • Geolocation

    • no additional parameters
  • UserConsent

    • title: string, content: string
  • Signature

    • title: (optional) string - Adds optional title to the top of the screen. Contains value of the title string key
    • description: (optional) string - Adds optional description below the title. Contains value of the description string key
    • descriptionMaxLines (optional): number - Specifies maximum amount of lines of text in the description
  • VideoSelfie: Available only for API level 21+.

    • showTutorial (optional, defaults to false): Show tutorial for video selfie.
    • selfieScanMode (optional, defaults to selfieMatch): selfieMatch | faceMatch; Specify if you would like to do selfie comparison, or comparison with the photo from ID.
    • selfieLivenessCheck (optional, defaults to false): Check for user liveness during video selfie.
    • showIdScan (optional, defaults to true): Ask for ID scan during video selfie.
    • showVoiceConsent (optional, defaults to true): Ask for Voice consent during video selfie
    • voiceConsentQuestionsCount (optional, defaults to 3): Choose number of questions for video selfie voice consent steps.
    • cameraFacingConfiguration (optional): CameraFacingConfiguration. Specifies which camera will be used during each step in Video selfie.
  • IdScan

    • showTutorial (optional, defaults to true): boolean
    • idType (optional): id or passport. If omitted, the app will display a chooser to the user.
    • idCategory (optional): primary or secondary. Default primary
    • showRetakeScreen (optional, defaults to true): boolean
    • enableFrontShownAsBackCheck (optional, defaults to false): boolean
    • enableBackShownAsFrontCheck (optional, defaults to false): boolean
    • showAutoCaptureRetakeScreen (optional, defaults to false): boolean
    • enableRotationOnRetakeScreen (optional, defaults to true): boolean
    • autocaptureUxMode (optional): countdown or holdStill. Default 'holdStill'
    • showIDOverlay (optional, defaults to false): boolean
    • streamFrames (optional): boolean. It requires RN SDK -vc variant, and additional com.incode.sdk:video-streaming:1.5.5 Android dependency added to the build.gradle
  • IdScanFront

    • showTutorial (optional, defaults to true): boolean
    • idType (optional): id or passport. If omitted, the app will display a chooser to the user.
    • idCategory (optional): primary or secondary. Default primary
    • showRetakeScreen (optional, defaults to true): boolean
    • enableFrontShownAsBackCheck (optional, defaults to false): boolean
    • enableBackShownAsFrontCheck (optional, defaults to false): boolean
    • showAutoCaptureRetakeScreen (optional, defaults to false): boolean
    • enableRotationOnRetakeScreen (optional, defaults to true): boolean
    • autocaptureUxMode (optional): countdown or holdStill. Default 'holdStill'
    • showIDOverlay (optional, defaults to false): boolean
    • streamFrames (optional): boolean. It requires RN SDK -vc variant, and additional com.incode.sdk:video-streaming:1.5.5 Android dependency added to the build.gradle
  • IdScanBack

    • showTutorial (optional, defaults to true): boolean
    • idCategory (optional): primary or secondary. Default primary
    • showRetakeScreen (optional, defaults to true): boolean
    • enableFrontShownAsBackCheck (optional, defaults to false): boolean
    • enableBackShownAsFrontCheck (optional, defaults to false): boolean
    • showAutoCaptureRetakeScreen (optional, defaults to false): boolean
    • enableRotationOnRetakeScreen (optional, defaults to true): boolean
    • autocaptureUxMode (optional): countdown or holdStill. Default 'holdStill'
    • showIDOverlay (optional, defaults to false): boolean
    • streamFrames (optional): boolean. It requires RN SDK -vc variant, and additional com.incode.sdk:video-streaming:1.5.5 Android dependency added to the build.gradle
  • ProcessId

    • enableIdSummaryScreen: boolean. Specifying false means no summary screen will be shown to the user once he fail to capture ID multiple times. Defaults to true.
  • Conference

    • disableMicOnStart: boolean
  • SelfieScan

    • showTutorial (optional, defaults to true): boolean
    • lensesCheck (optional, defaults to true): boolean. Performs check if user is wearing glasses during Selfie Scan.
    • cameraFacing (optional, defaults to front): front | back. Specifies which camera will be used during Selfie capture.
    • faceMaskCheck (optional, defaults to false): boolean. This checks if a person has a mask on.
    • brightnessThreshold (optional, defaults to 50): number. Adjust minimum requirements for a well lit face during capture.
    • streamFrames (optional): boolean. It requires RN SDK -vc variant, and additional com.incode.sdk:video-streaming:1.5.5 Android dependency added to the build.gradle
  • FaceMatch

    • idCategory (optional): primary or secondary. Default primary
    • showUserExists (optional): defaults to true: boolean
    • Note: has to be specified after IDScan and SelfieScan modules.
  • QrScan

    • no additional parameters
  • Email

    • no additional parameters
  • Approve

    • forceApproval (optional, defaults to false): boolean - if true the user will be force-approved
  • UserScore

    • mode (optional, defaults to accurate): accurate or fast. If accurate the results will be fetched from server, which may exhibit some latency, but will rely on server-side processing of information, which may be more reliable than on-device processing. If fast, then results based on on-device processing will be shown.
  • MLConsent

    • type: gdpr | us
  • GovernmentValidation

    • isBackgroundExecuted (optional): defaults to false: boolean
  • Antifraud

    • no additional parameters
  • GlobalWatchlist

    • no additional parameters
  • CustomWatchlist

    • no additional parameters
  • Aes

    • uploadDocument (optional): defaults to false: boolean
    • downloadDocument (optional): defaults to false: boolean
  • Name

    • no additional parameters
  • CURP

    • validationEnabled (optional): defaults to true: boolean - Specifies should the CURP be validated on the server or not.
  • OCREdit

    • isEditable (optional): defaults to false: boolean
  • eKYB

    • checkBusinessName (optional): defaults to false: boolean
    • checkAddress (optional): defaults to false: boolean
    • checkTaxId (optional): defaults to false: boolean
  • eKYC

    • checkName (optional): defaults to false: boolean
    • checkEmail (optional): defaults to false: boolean
    • checkAddress (optional): defaults to false: boolean
    • checkPhone (optional): defaults to false: boolean
    • checkSsn (optional): defaults to false: boolean
    • checkDob (optional): defaults to false: boolean
    • checkNationality (optional): defaults to false: boolean

Flow listeners

The SDK offers several types of listeners:

  • user cancellation
  • tracking events
  • step completion, for each module individually
  • step error, for each module individually
  • step update, for each module individually

User cancellation

If the user cancels the onboarding, startOnboarding and startWorkflow method result would have status - 'userCancelled'.
On both platforms the user can cancel by pressing 'X' button that can be enabled using IncodeSdk.showCloseButton(true);, and additionally on Android the user can cancel by pressing the back key.

Tracking events

  • When onboarding has been started, information about events used to track all the user steps in their flow can be obtained using onEvents callback.
IncodeSdk.onEvents((e) => {
  for (const ev of e.events) {
    console.log(ev.event);
  }
});
  • e: Events - Parameter holding array of all events
  • events: EventDetails[] - Array of emitted events
  • event: Event - Event with fields:
    • event: string - Unique identifier of the event
    • data: string - JSON string with additional event details

Step completion

When onboarding session gets created, the information about the session can be obtained via IncodeSdk.onSessionCreated method.

IncodeSdk.onSessionCreated((session) => {
  console.log(
    'Onboarding session created, interviewId: ' + session.interviewId
  );
});
  • interviewId: String - Unique identifier of the onboarding session
  • token: String - Token created for this onboarding session

Note This method should be called before startOnboarding

When a step within the configured Onboarding flow is completed, the information can be obtained by registering a listener via IncodeSdk.onStepCompleted. This takes two arguments: (1) the module name and (2) the callback.

IncodeSdk.onStepCompleted({
  module: 'SelfieScan',
  listener: (selfieScanResult) => {
    console.log('SELFIE SCAN completed', selfieScanResult.result);
  },
});

IdScanFront

  • image: IncdImage object, containing pngBase64 of the captured front ID
  • croppedFace: IncdImage object, containing pngBase64 of the cropped face from the front ID
  • classifiedIdType: the String - Classified ID type by Incode, ie. Voter Identification
  • chosenIdType: the String - what did the user choose to capture id or passport
  • idCategory: String, category of the ID verified primary or secondary
  • status: the String . If value is other than ok you can consider the ID scan and/or validation did not come through successfully. The Incode UI will clearly inform the user about these errors and will attempt the scan several times, before responding with an error. Possible error values: errorClassification, noFacesFound, errorGlare, errorReadability, errorSharpness, errorTypeMismatch, userCancelled, unknownError, errorClassification, errorShadow, errorPassportClassification.

IdScanBack

  • image: IncdImage object, containing pngBase64 of the captured front ID
  • classifiedIdType: the String - Classified ID type by Incode, ie. Voter Identification
  • chosenIdType: the String - what did the user choose to capture id or passport
  • idCategory: String, category of the ID verified primary or secondary
  • status: the String . If value is other than ok you can consider the ID scan and/or validation did not come through successfully. The Incode UI will clearly inform the user about these errors and will attempt the scan several times, before responding with an error. Possible error values: errorClassification, noFacesFound, errorGlare, errorReadability, errorSharpness, errorTypeMismatch, userCancelled, unknownError, errorClassification, errorShadow, errorPassportClassification.

Notes:

  • result.data.birthDate is the epoch time.
  • result.status.back and result.status.front can take one of following values: ok or several others indicating an issue with the scanning. The Incode UI will clearly inform the user about these errors and will attempt the Scan several times, before responding with an error. Other errors are: errorClassification, noFacesFound, errorCropQuality, errorGlare, errorReadability, errorSharpness, errorTypeMismatch, userCancelled, unknownError, errorClassification, shadow, errorAddress, errorPassportClassification, errorReadability.

ProcessId

  • data: the basic IdScanOcrData object, containing most important data
  • ocrData: the String object, raw JSON containing full OCR data ie. exteriorNumber, interiorNumber, typeOfId, documentFrontSubtype

Notes:

  • result.data.birthDate is the epoch time.

Conference

This module starts a video conference call with the executive.

Example response for completion of the step:

{
  "step": "Conference",
  "result": {
    "status": "success"
  }
}

Example response for error of the step:

{
  "step": "Conference",
  "result": {
    "status": "error"
  }
}

The field result.status can have values userCancelled, invalidSession or error;

DocumentScan

The DocumentScan will attempt reading address from the provided document.

Note: If the user decides to skip this step, you will get a response with blank values, instead of nil/error.

Example response for completion of the step:

{
  "result": {
    "address": { // parsed OCR data
      "city": "Springfield",
      "colony": "Springfield",
      "postalCode": "555555",
      "state": "Serbia",
      "street": "Evergreen terrace"
    },
    "data": {"raw JSON OCR data"},
    "type": "addressStatement",
    "image": {"pngBase64": "/9j/4AAQSkZJRgABAQAAAQABAAD/4..."},
  },
  "step": "DocumentScan"
}

Example response for error of the step:

{
  "status": "userCancelled",
  "step": "DocumentScan"
}

The field status can have one of the following values: permissionsDenied, simulatorDetected or unknown.

Geolocation

The Geolocation steps yields the current location of the user. Example response for completion of the step:

{
  "result": {
    "city": "Springfield",
    "colony": "Springfield",
    "postalCode": "555555",
    "state": "Serbia",
    "street": "Evergreen terrace"
  },
  "step": "Geolocation"
}

The field status can have one of the following values: permissionsDenied, unknownError or noLocationExtracted.

UserConsent

In case the user has given the consent:

{
  "status": "success",
  "step": "UserConsent"
}

If the user declined to give the consent, the onboarding flow will be ended with a status userCancelled.

MLConsent

In case the user has given the machine learning consent:

{
  "status": "success",
  "step": "MLConsent"
}

If some error happened, the "status" field will be set to corresponding error.
If the user declined to give the consent, the onboarding flow will be ended with a status userCancelled.

GovernmentValidation

This module enables your user to input their information to validate with Government services as a part of your flow.

On module completion, the result returned will look like this:

{
  "status": "success",
  "step": "GovernmentValidation"
}

The field status can have one of the following values: success or fail.

Antifraud

This module gives ability to compare current interview with existing interviews and customers and detect anomalies that could be signs of fraud.

On module completion, the result returned will look like this:

{
  "status": "success",
  "step": "Antifraud"
}

The field status can have one of the following values: success or fail.

Name

This module enables to capture user's name as a part of your flow.

On module completion, the result returned will look like this:

{
  "status": "success",
  "name": "exampleName",
  "step": "Name"
}

The field status can have one of the following values: success or fail.

CURP

This module enables your user to input their CURP information to validate with RENAPO service as a part of your flow. (CURP is a person identifier in México)

On module completion, the result returned will look like this:

{
  "status": "success",
  "curp": "exampleCurp",
  "step": "CURP"
}

The field status can have one of the following values: success or fail.

OCREdit

This module will show to the user parsed OCR from his ID, which can be optionally edited.

On module completion, the result returned will look like this:

{
  "status": "success",
  "step": "OCREdit"
}

The field status can have one of the following values: success or fail.

eKYB

This module enables a step of KYB validation with the business information and an option of source for this information which includes business name, addresses, city, state, postal code and bank account number.

On module completion, the result returned will look like this:

{
  "status": "success",
  "step": "eKYB"
}

The field status can have one of the following values: success or fail.

eKYC

This module enables a step of kyc validation with the user's information and an option of source for this information which includes data obtained from id, proof of address, or a manual capture.

On module completion, the result returned will look like this:

{
  "status": "success",
  "step": "eKYC"
}

The field status can have one of the following values: success or fail.

GlobalWatchlist

This module checks customer identities against sources of Sanctions, Politically Exposed Persons (PEPs), & Watchlists.

On module completion, the result returned will look like this:

{
  "status": "success",
  "step": "GlobalWatchlist"
}

The field status can have one of the following values: success or fail.

CustomWatchlist

This module checks if the user is found on the watchlist. Watchlist is configured in incode's dashboard.

On module completion, the result returned will look like this:

{
  "status": "success",
  "step": "CustomWatchlist"
}

The field status can have one of the following values: success or fail.

Aes

This module enables an advanced electronic signature to ensure legally binding and compliant document signing with enhanced security and authentication measures.

On successfull module completion, the result returned will look like this:

{
  "status": "success",
  "step": "Aes"
}

The field status can have one of the following values: success or fail.

Example response for error of the step:

{
  "status": "fail",
  "error": "noDocuments",
  "step": "Aes"
}

FaceMatch

This module checks if the face from the scanned ID/passport and the face obtained from the SelfieScan module are a match.

Example response for completion of the step:

{
  "result": {
    "status": "match",
    "confidence": 1,
    "nameMatched": false,
    "existingUser": false,
    "existingInterviewId": "exampleInterviewID",
    "idCategory": "primary"
  },
  "step": "FaceMatch"
}

The field result.status can take values match or mismatch.
Example response for error of the step:

{
  "status": "userCancelled",
  "step": "FaceMatch"
}

The field status can have one of values: unknownError or simulatorDetected.

Phone

This module enables the user to enter their phone number.
Example response for completion of the step:

{
  "result": { "phone": "+15555555555", "resultCode": "success" },
  "step": "Phone"
}

The field result.resultCode can take the value success.

Example response for error of the step:

{
  "status": "error",
  "step": "Phone"
}

The field status can take one of the values: invalidSession, userCancelled, error.

Email

This module enables the user to enter their email.
Example response for completion of the step:

{
  "result": { "email": "[email protected]", "status": "success" },
  "step": "Email"
}

Example response for error of the step:

{
  "status": "fail",
  "step": "Email"
}

Signature

This module enables user to add a digital signature by signing on a canvas.

Besides sepcifying title and description keys it is needed to provide texts for Android and iOS in their res/values/strings.xml and Localizable.strings files.

{
  module: 'Signature',
  title: 'onboard_sdk_signature_title',
  description: 'onboard_sdk_signature_description',
  descriptionMaxLines: 2
}

For Android:

<string name="onboard_sdk_signature_title">Example title</string>
<string name="onboard_sdk_signature_description">Description example</string>

For iOS:

"onboard_sdk_signature_title" = "Example title";
"onboard_sdk_signature_description" = "Description example";

Example response for completion of the step:

{
  "result": { "status": "success", "image": "...PNG Base 64 encoded" },
  "step": "Signature"
}

Example response for error of the step:

{ "status": "error", "step": "Signature" }

The field status can take one of following: error or invalidSession.

SelfieScan

Example result:

{
  "result": { "spoofAttempt": false, "status": "success" },
  "step": "SelfieScan",
  "image": {
    "pngBase64": "...PNG Base 64 encoded",
    "encryptedBase64": "...PNG Encyrpted Base 64 encoded"
  }
}

Example response for error of the step:

{
  "status": "success",
  "step": "SelfieScan"
}

The field status can take one of the values: none, permissionsDenied, simulatorDetected, spoofDetected.

Approve

Adding this module to the flow instructs the Incode server to perform the approval of the user.

Example response for completion of the module:

{ "result": { "status": "approved", "id": "customerUUID", "customerToken": "customerToken"}}, "step": "Approve" }
  • The field status can take values: approved and failed.

Example response for error of the module: there is no error.

UserScore

This module displays the user score using the UI.

Example response for completion of the module:

{
  "result": {
    "data": {
      "existingUser": true,
      "facialRecognitionScore": "0.0/100",
      "idVerificationScore": "79.0/100",
      "livenessOverallScore": "95.2/100",
      "overallScore": "0.0/100",
      "status": "fail"
    },
    "extendedUserScoreJsonData": "{..}"
  },
  "step": "UserScore"
}

data will contain basic parsed users core data.
extendedUserScoreJsonData will contain raw JSON containing full user score data.

Example response for error of the module:
The field result.data.status can have one of the following values: warning, unknown, manual and fail.

QrScan

This module captures the QR code on the back of the ID, extracts the valuable data out of it and sends it to the server.

VideoSelfie

This module records the device's screen while the user needs to do a selfie, show his ID, answer a couple of questions and confirms that he accept the terms and conditions. The recorded video is then uploaded and stored for later usage.

Captcha

This module asks the user to enter OTP generated for current session.
If the user doesn't enter correct OTP multiple times the flow will be terminated.
On module completion, the result given to the listener will take the shape of:

{
  "result": {
    "status": "success",
    "response": "ABCDEF"
  }
}

Note: Captcha failure will result in rejection of Onboarding promise. There is no module error listener here.

Other API methods

Incode's SDK exposes additional operations: Face login, user approve and user score.

Face Login

Prerequisites for a successful Face Login is that user has an approved account with an enrolled face.

Face Login 1:1

1:1 Face Login performs a 1:1 face comparison, and returns a successful match if the two faces match.

For 1:1 Face login you nned to have at hand his customerUUID. If the user was approved during onboarding on mobile device, you should have received customerUUID as a result of Approve step during onboarding.

Example usage:

const runLogin = async () => {
    try {
      await IncodeSdk.initialize({
        testMode: false,
        apiConfig: {
          key: 'YOUR API KEY',
          url: 'YOUR API URL',
        },
      });
    } catch (error) {
      const e = error as IncodeSdkInitError;
      console.error(e.code + " - " + e.message)
    }

    IncodeSdk.startFaceLogin({
      showTutorials: true,
      faceMaskCheck: false, // Specify true if you would like to prevent login for users that wear face mask
      customerUUID: 'YOUR_CUSTOMER_UUID',
      lensesCheck: false,
      brightnessThreshold: 50,
      logAuthenticationEnabled: false,
    }
      ).then( (faceLoginResult) => {
        console.log(faceLoginResult)
      })
      .catch((e) => {
        console.error(e.code + " - " + e.message)
      });
  };

Note To enable faceMaskCheck on Android, please add additional dependency to the build.gradle:

  dependencies {
    ...
+   implementation 'com.incode.sdk:model-mask-detection:2.0.0'
    ...
  }

Example Face Login 1:1 response:

{
  "faceMatched": true, // boolean indicator if Face Login was successful. Reason for faiulure might be that faces didn't match, or the user with this customerToken and customerUUID isn't found in the system.
  "spoofAttempt": false, // boolean indicator if face login failed due to spoof attempt
  "image": {
    "pngBase64": "...PNG Base 64 encoded",
    "encryptedBase64": "...PNG Encyrpted Base 64 encoded"
  },
  "customerUUID": "exampleCustomerUUID", // Approved customer ID
  "interviewId": "exampleInterviewID", // Interview ID of the session where the user got approved
  "interviewToken": "exampleInterviewToken", // Interview token of the session where the user got approved
  "token": "exampletoken", // Fewshly generated token for now authenticated user
  "transactionId": "Unique Authentication attempt ID", // Unique ID of this authentication attempt
  "hasFaceMask": false // boolean indicator if person was wearing a face mask during login. Available in iOS only, Anddroid will force the user to take the mask off before login is performed.
}

Face Login 1:N

1:N Face Login performs a 1:N database face lookup, and returns a successful match if face is found in the database.

Example usage:

const runLogin = async () => {
    try {
      await IncodeSdk.initialize({
        testMode: false,
        apiConfig: {
          key: 'YOUR API KEY',
          url: 'YOUR API URL',
        },
      });
    } catch (error) {
      const e = error as IncodeSdkInitError;
      console.error(e.code + " - " + e.message)
    }

    IncodeSdk.startFaceLogin({
      showTutorials: true,
      faceMaskCheck: false, // Specify true if you would like to prevent login for users that wear face mask
      lensesCheck: false,
      brightnessThreshold: 50,
      logAuthenticationEnabled: false,
    }
      ).then( (faceLoginResult) => {
        console.log(faceLoginResult)
      })
      .catch((e) => {
        console.error(e.code + " - " + e.message)
      });
  };

Note To enable faceMaskCheck on Android, please add additional dependency to the build.gradle:

  dependencies {
    ...
+   implementation 'com.incode.sdk:model-mask-detection:2.0.0'
    ...
  }

Example Face Login 1:N response:

{
  "faceMatched": true, // boolean indicator if Face Login was successful. Reason for faiulure might be that this face isn't associated with any approved user in the database.
  "spoofAttempt": false, // boolean indicator if face login failed due to spoof attempt
  "image": {
    "pngBase64": "...PNG Base 64 encoded",
    "encryptedBase64": "...PNG Encyrpted Base 64 encoded"
  },
  "customerUUID": "exampleCustomerUUID", // Approved customer ID
  "interviewId": "exampleInterviewID", // Interview ID of the session where the user got approved
  "interviewToken": "exampleInterviewToken", // Interview token of the session where the user got approved
  "token": "exampletoken", // Fewshly generated token for now authenticated user
  "transactionId": "Unique Authentication attempt ID", // Unique ID of this authentication attempt
  "hasFaceMask": false // boolean indicator if person was wearing a face mask during login. Available in iOS only, Anddroid will force the user to take the mask off before login is performed.
}

Get user score API

To fetch user score programmatically in order to evaluate it, you can use IncodeSdk.getUserScore.

When the promise is fulfilled, the result will contain all the data like in the result field of the corresponding User Score step.

Configuration is similar to User Score step: this method can receive optional config parameter map: {mode: 'accurate'}. The mode parameter is optional: can take values accurate or fast.

If config object or the mode is absent, then accurate is the default;

IncodeSdk.getUserScore()
  .then((score) => console.log(score))
  .catch((e) => {
    console.error('Face match failed', e);
  });

Approve API

To programmatically initiate approval of the user, you can use IncodeSdk.approve. It takes a config object, setting forceApprove (see approve module). When the promise is fulfilled, the result will contain all the data like in the result field of the corresponding Approve step.

IncodeSdk.approve({ forceApproval: false })
  .then((result) => {
    console.log('approve finished: ', result);
  })
  .catch((e) => {
    console.log('approve error: ', e);
  });

FaceMatch API

To programmatically initiate face match between photo from the ID and Selfie, you can use IncodeSdk.faceMatch. It does the matching silently in the background, comapring to regular Face Match module that shows UI feedback to the user.

IncodeSdk.faceMatch()
  .then((faceMatchResult) => {
    console.log('Face match result: ', faceMatchResult);
  })
  .catch((e) => {
    console.error('Face match failed', e);
  });

Delete Local User Data API

To programmatically delete localy stored onboarding session data on Android devices, you can use IncodeSdk.deleteUserLocalData. This will delete up to 5-6 MB of data stored on local storage during onboarding flow.

IncodeSdk.deleteUserLocalData();

Show close button during the flow

To programatically show the 'X' button on the top right corner during the flow, call IncodeSdk.showCloseButton.
Once user clicks the 'X' button the flow will be aborted.

IncodeSdk.showCloseButton(true);

Set Localization Language

To programatically set localization language in runtime, call IncodeSdk.setLocalizationLanguage.
Parameters available for IncodeSDK.setLocalizationLanguage method:

  • language - language used for runtime localization. Supported values are currently: 'en', 'es' , 'pt'.
IncodeSdk.setLocalizationLanguage('en');

Additionally, on Android platform a new dependency needs to be added in your app's build/gradle:

  implementation 'com.incode.sdk:extensions:1.1.0'

Set string

To programatically set and update strings in runtime, call IncodeSdk.setString.
Parameters available for IncodeSDK.setString method:

  • strings: { [key: string]: string }. Map of string keys and its values.
IncodeSdk.setString({
  /// iOS labels
  'incdOnboarding.idChooser.idButton': 'Id',
  /// Android labels
  'onboard_sdk_btn_passport': 'Passport',
});

Additionally, on Android platform a new dependency needs to be added in your app's build/gradle:

  implementation 'com.incode.sdk:extensions:1.1.0'

For iOS please check documentation here:
https://developer.incode.com/docs/localization-guide#list-of-localizable-texts

For Android please check documentation here:
https://developer.incode.com/docs/user-guide-customization#32-dynamic-localization

Sections execution API

The Sections execution API enables you to design a flow which executes in sections, whereas the regular onboarding flow is executed in a single go. You'd typically use this method to evaluate results of a module (e.g. ID Scan) in order to choose whether or not other modules (e.g. Geolocation) are needed. In this case ID Scan would be executed in one section, and Selfie would be executed in the following. In between sections, the Incode's UI goes away, and you can have your own business logic getting executed or show your own UI screens.

Here's full code sample:

import React from 'react';
import IncodeSdk from '@incode-sdks/react-native-incode-sdk';
import { View, TouchableOpacity } from 'react-native';

const StartSectionedOnboardingButton = () => {
  const [addressCity, setAddressCity] = useState(null);

  const executeSectionedFlow = async () => {
    try {
      await IncodeSdk.initialize({
        testMode: false,
        apiConfig: {
          key: 'YOUR API KEY',
          url: 'YOUR API URL',
        },
      });
    } catch (error) {
      const e = error as IncodeSdkInitError;
      console.error(e.code + " - " + e.message)
    }

    const session = await IncodeSdk.setupOnboardingSession({});
    const idSection = await IncodeSdk.startOnboardingSection({
      flowConfig: [
        {
          module: 'IdScan',
        },
      sectionTag: 'idSection',
      ],
    });

    // insert optional custom business logic

    await IncodeSdk.startOnboardingSection({
        flowConfig: [{ module: 'SelfieScan' }],
        sectionTag: 'selfieSection',
    });
    IncodeSdk.finishOnboardingFlow();
    unregisterIdScanListener();
  };

  return <TouchableOpacity label="Start sections" onPress={executeSectionedFlow} />;
};

Init the SDK

Parameters available for IncodeSDK.initialize method:

  • testMode - Set to true if running on simulator/emulators, false when running on devices. Default false.
  • sdkMode - Specify standard or captureOnly modes. Default is standard. captureOnly mode works completely offline and for ID and Selfie scan only does image captures without doing any validations.
  • disableHookCheck - Set to true if you would like to test the app on Android devices that have some hook frameworks installed, cause they are not allowed in production. Default false.
  • apiConfig
    • key [optional] - API key, provided by Incode
    • url - API url, provided by Incode

Possible error codes and error messages during initialize:

Incd::EmulatorDetected - “Emulator detected, emulators aren't supported in non test mode!”
Incd::RootDetected - “Root access detected, rooted devices aren't supported in non test mode!”
Incd::HookDetected - “Hooking framework detected, devices with hooking frameworks aren't supported in non test mode!”
Incd::TestModeDetected - “Please disable test mode before deploying to a real device!”

Setup the onboarding session

To setup an onboarding session call setupOnboardingSession method:

const session = await IncodeSdk.setupOnboardingSession({});

In case you would like to change session parameters, specify them inside optional sessionConfig parameter:

  • region - Specify a region, currently supported are ALL(covers all regions), BR (optimized for Brazil) and IN (optimized for India)
  • queue - Specify a queue to which this onboarding session will be attached to
  • interviewId - In case you're creating an onboarding session on the backend, you can provide its interviewId and the flow will be started for that particular onboarding session
  • configurationId - In case you've created a flow on the dashboard with a specific configuration, you can provide it here so that those settings apply to this session
  • token - In case you're creating an onboarding session on the backend, you can provide its token and the flow will be started for that particular onboarding session
  • externalId - ID used outside of Incode Omni
  • validationModules - List of validation modules that should be enabled in this session
  • customFields - Custom data that should be attached to this onboarding session
  • e2eEncryptionEnabled - Enable e2e encryption.

List of available validation modules:

id - enables ID validation for the session
liveness - enables spoof detection during Selfie for the session
faceRecognition - enables Face Match comparison between photo from the ID and Selfie
governmentValidation - enables govermnent validation of the ID
governmentFaceValidation - enables govermnent validation of face from the Selfie
governmentOcrValidation - enables govermnent validation of the OCR data from the ID
videoSelfie - enables Video selfie results being part of scoring for the session

Default validation modules are: id, liveness, and faceRecognition.

Return values of setupOnboardingSession method:

  • token: String - Token of the onboarding session
  • interviewId: String - Unique identifier of the onboarding session

Start the section

To configure and start the flow for a section use startOnboardingSection method:

const idSection = await IncodeSdk.startOnboardingSection({
  flowConfig: [
    {
      module: 'IdScan',
    },
  ],
  sectionTag: 'idSection',
});

You can start multiple sections, but only one at a time.
startOnboardingSection accepts the same config and modules as startOnboarding method, so please take a look at Supported modules section above.

Optionally, specify sectionTag parameter to uniquely identify section you want to start.

To enable screen recording of ID and Selfie capture, specify optional recordSessionConfig parameter:

  • Set recordSession to true
  • Set forcePermissions, true if you wish to abort the session in case user denies permissons, false otherwise

Return values:

  • status: String. 'success' or 'userCancelled'.
  • sectionTag: String. value of sectionTag parameter passed in config.

To get results from the steps within the section, please take a look at the Step completion section above.

Finish the flow

Once all the sections are completed you'll have to finish current onboarding session. To do so, call finishOnboardingFlow method:

IncodeSdk.finishOnboardingFlow();

Using SDK without an API KEY

To use the SDK without an API KEY, please provide a token to the setupOnboardingSession method, and afterwards you should proceed with using Sections API like in the example below:


    try {
      await IncodeSdk.initialize({
        testMode: false,
        apiConfig: {
          url: 'YOUR API URL',
        },
      });
    } catch (error) {
      const e = error as IncodeSdkInitError;
      console.error(e.code + " - " + e.message)
    }

    IncodeSdk.setupOnboardingSession({
        sessionConfig: {
          token: 'YOUR_TOKEN',
         }
        }).then((sessionResult) => {
          IncodeSdk.startOnboardingSection({
            flowConfig: [{ module: 'IdScan', showTutorial: false },
                     { module: 'SelfieScan', showTutorial: false},],
          })
            .then((onboardingSectionResult) => {
              IncodeSdk.faceMatch()
              .then((faceMatchResult) => {
                IncodeSdk.finishOnboardingFlow()
                .then((finishResult) => {
                  console.log('Session completed successfully');
                })
                .catch((e) => {
                  console.error('Finish session error', e);
                })
              })
              .catch((e) => {
                console.error('Face match error', e);
              })
            })
            .catch((e) => {
              console.error('Start onboarding section error', e);
            });
         })
         .catch((e) => {
          console.error('Set onboarding session error', e);
         });

SDK impact size optimizations

To programmatically delete locally stored onboarding session data on Android devices, refer to the section here

Dynamic Delivery

To use Dynamic Delivery of the resources on Android and iOS platforms, please follow the guide here

E2EE SDK Integration Guide

End-to-End Encryption (E2EE) adds an extra layer of security to your communications by encrypting the data transmitted between the server and client. The process begins with a key exchange where the client and server share keys for encrypting and decrypting messages. This exchange acts like a handshake and ensures that all subsequent communications are encrypted. Only the intended server and client are able to decrypt the messages.

Steps to Enable E2EE in the SDK.

1. Install SDK variant with e2ee support

npm i @incode-sdks/react-native-incode-sdk-e2ee

2. Set Up a Custom Server for E2EE

Initialize the SDK with a custom server for E2EE as follows:

IncodeSdk.initialize({
  apiConfig: {
    key: 'YOUR API KEY HERE',
    url: 'YOUR API URL HERE',
    e2eeUrl: 'YOUR E2EE URL HERE',
  },
});

3. Enable E2EE via SessionConfig

const sessionConfig: OnboardingSessionConfig = {
  e2eEncryptionEnabled: true,
};

4. Pass the SessionConfig Object

You can pass the SessionConfig object to SDK when setup onboarding session:

const session = await IncodeSdk.setupOnboardingSession(sessionConfig);

or when starting a flow:

await IncodeSdk.startOnboarding({
  sessionConfig,
  flowConfig,
});

Customization

The customization is done independently for both platforms.

Android

  • To change the texts, add other localization to the app, change icons or videos or customize the theme check the full guide here.

iOS

  • To change icons or videos guide, please follow the guide here.
  • To change the texts, add other localization to the app, please follow the guide here
  • To change the theme use setTheme method, as in the following example:
const jsonTheme = JSON.stringify({
                "colors": {
                  "accent": "#00B2FD",
                  "primary": "#20263D",
                  "background": "#FFFFFF",
                  "secondaryBackground": "#E9E9EB",
                  "success": "#0CD5A2",
                  "error": "#FF5C6F",
                  "warning": "#F3AB3C",
                  "cancel": "#20263D"
                },
                "fonts": {
                  "buttonBig": {
                    "name": "CircularXXTT-Black",
                    "size": "20"
                  },
                  "buttonMedium": {
                    "name": "CircularXXTT-Black",
                    "size": "16"
                  },
                  "buttonSmall": {
                    "name": "CircularXXTT-Black",
                    "size": "12"
                  },
                  "title": {
                    "name": "CircularXXTT-Black",
                    "size": "25"
                  },
                  "hugeTitle": {
                    "name": "CircularXXTT-Black",
                    "size": "40"
                  },
                  "subtitle": {
                    "name": "CircularXXTT-Black",
                    "size": "18"
                  },
                  "boldedSubtitle": {
                    "name": "CircularXXTT-Bold",
                    "size": "18"
                  },
                  "smallSubtitle": {
                    "name": "CircularXXTT-Black",
                    "size": "14"
                  },
                  "info": {
                    "name": "CircularXXTT-Black",
                    "size": "16"
                  },
                  "body": {
                    "name": "CircularXXTT-Medium",
                    "size": "14"
                  },
                  "boldedBody": {
                    "name": "CircularXXTT-Bold",
                    "size": "14"
                  },
                  "textFieldBig": {
                    "name": "CircularXXTT-Black",
                    "size": "20"
                  },
                  "textFieldMedium": {
                    "name": "CircularXXTT-Black",
                    "size": "15"
                  }
                },
                "buttons": {
                  "primary": {
                    "states": {
                      "normal": {
                        "animateStateChange": true,
                        "alpha": 1,
                        "backgroundColor": "#00B2FD",
                        "borderColor": "",
                        "borderWidth": 0,
                        "cornerRadius": 32,
                        "shadowColor": "#000000",
                        "shadowOffset": [0,5],
                        "shadowOpacity": 0.15,
                        "shadowRadius": 9,
                        "textColor": "#FFFFFF",
                        "transform": {
                          "a": 1,
                          "b": 0,
                          "c": 0,
                          "d": 1,
                          "tx": 0,
                          "ty": 0
                        }
                      },
                      "highlighted": {
                        "animateStateChange": true,
                        "alpha": 1,
                        "backgroundColor": "#20263D",
                        "borderColor": "",
                        "borderWidth": 0,
                        "cornerRadius": 32,
                        "shadowColor": "#000000",
                        "shadowOffset": [0,5],
                        "shadowOpacity": 0.15,
                        "shadowRadius": 9,
                        "textColor": "#00B2FD",
                        "transform": {
                          "a": 1,
                          "b": 0,
                          "c": 0,
                          "d": 1,
                          "tx": 0,
                          "ty": 0
                        }
                      },
                      "disabled": {
                        "animateStateChange": true,
                        "alpha": 1,
                        "backgroundColor": "#E9E9EB",
                        "borderColor": "",
                        "borderWidth": 0,
                        "cornerRadius": 32,
                        "shadowColor": "#000000",
                        "shadowOffset": [0,5],
                        "shadowOpacity": 0,
                        "shadowRadius": 9,
                        "textColor": "#FFFFFF",
                        "transform": {
                          "a": 1,
                          "b": 0,
                          "c": 0,
                          "d": 1,
                          "tx": 0,
                          "ty": 0
                        }
                      }
                    },
                    "big": {
                      "height": 64,
                      "minWidth": 200,
                      "contentInsets": {
                        "top": 19,
                        "left": 32,
                        "bottom": 19,
                        "right": 32
                      },
                      "kerning": 0
                    },
                    "medium": {
                      "height": 46,
                      "minWidth": 0,
                      "contentInsets": {
                        "top": 12,
                        "left": 24,
                        "bottom": 12,
                        "right": 24
                      },
                      "kerning": 0
                    }
                  },
                  "secondary": {
                    "states": {
                      "normal": {
                        "animateStateChange": true,
                        "alpha": 1,
                        "backgroundColor": "#FFFFFF",
                        "borderColor": "#20263D",
                        "borderWidth": 1,
                        "cornerRadius": 32,
                        "shadowColor": "",
                        "shadowOffset": [0,0],
                        "shadowOpacity": 0,
                        "shadowRadius": 0,
                        "textColor": "#20263D",
                        "transform": {
                          "a": 1,
                          "b": 0,
                          "c": 0,
                          "d": 1,
                          "tx": 0,
                          "ty": 0
                        }
                      },
                      "highlighted": {
                        "animateStateChange": true,
                        "alpha": 1,
                        "backgroundColor": "#20263D",
                        "borderColor": "#20263D",
                        "borderWidth": 1,
                        "cornerRadius": 32,
                        "shadowColor": "",
                        "shadowOffset": [0,0],
                        "shadowOpacity": 0,
                        "shadowRadius": 0,
                        "textColor": "#00B2FD",
                        "transform": {
                          "a": 1,
                          "b": 0,
                          "c": 0,
                          "d": 1,
                          "tx": 0,
                          "ty": 0
                        }
                      },
                      "disabled": {
                        "animateStateChange": true,
                        "alpha": 1,
                        "backgroundColor": "#FFFFFF",
                        "borderColor": "#E9E9EB",
                        "borderWidth": 1,
                        "cornerRadius": 32,
                        "shadowColor": "",
                        "shadowOffset": [0,0],
                        "shadowOpacity": 0,
                        "shadowRadius": 0,
                        "textColor": "#E9E9EB",
                        "transform": {
                          "a": 1,
                          "b": 0,
                          "c": 0,
                          "d": 1,
                          "tx": 0,
                          "ty": 0
                        }
                      }
                    },
                    "big": {
                      "height": 64,
                      "minWidth": 200,
                      "contentInsets": {
                        "top": 19,
                        "left": 32,
                        "bottom": 19,
                        "right": 32
                      },
                      "kerning": 0
                    },
                    "medium": {
                      "height": 46,
                      "minWidth": 0,
                      "contentInsets": {
                        "top": 12,
                        "left": 24,
                        "bottom": 12,
                        "right": 24
                      },
                      "kerning": 0
                    }
                  },
                  "text": {
                    "states": {
                      "normal": {
                        "animateStateChange": true,
                        "alpha": 1,
                        "backgroundColor": "",
                        "borderColor": "",
                        "borderWidth": 0,
                        "cornerRadius": 0,
                        "shadowColor": "",
                        "shadowOffset": [0,0],
                        "shadowOpacity": 0,
                        "shadowRadius": 0,
                        "textColor": "#20263D",
                        "transform": {
                          "a": 1,
                          "b": 0,
                          "c": 0,
                          "d": 1,
                          "tx": 0,
                          "ty": 0
                        }
                      },
                      "highlighted": {
                        "animateStateChange": true,
                        "alpha": 1,
                        "backgroundColor": "",
                        "borderColor": "",
                        "borderWidth": 0,
                        "cornerRadius": 0,
                        "shadowColor": "",
                        "shadowOffset": [0,0],
                        "shadowOpacity": 0,
                        "shadowRadius": 0,
                        "textColor": "#00B2FD",
                        "transform": {
                          "a": 1,
                          "b": 0,
                          "c": 0,
                          "d": 1,
                          "tx": 0,
                          "ty": 0
                        }
                      },
                      "disabled": {
                        "animateStateChange": true,
                        "alpha": 1,
                        "backgroundColor": "",
                        "borderColor": "",
                        "borderWidth": 0,
                        "cornerRadius": 0,
                        "shadowColor": "",
                        "shadowOffset": [0,0],
                        "shadowOpacity": 0,
                        "shadowRadius": 0,
                        "textColor": "#E9E9EB",
                        "transform": {
                          "a": 1,
                          "b": 0,
                          "c": 0,
                          "d": 1,
                          "tx": 0,
                          "ty": 0
                        }
                      }
                    },
                    "big": {
                      "height": 40,
                      "minWidth": 200,
                      "contentInsets": {
                        "top": 8,
                        "left": 16,
                        "bottom": 8,
                        "right": 16
                      },
                      "kerning": 0
                    },
                    "medium": {
                      "height": 30,
                      "minWidth": 0,
                      "contentInsets": {
                        "top": 12,
                        "left": 24,
                        "bottom": 12,
                        "right": 24
                      },
                      "kerning": 0
                    }
                  },
                  "help": {
                    "states": {
                      "normal": {
                      "animateStateChange": true,
                      "alpha": 1,
                      "backgroundColor": "#FFFFFF",
                      "borderColor": "",
                      "borderWidth": 0,
                      "cornerRadius": 20,
                      "shadowColor": "#000000",
                      "shadowOffset": [0,5],
                      "shadowOpacity": 0.15,
                      "shadowRadius": 9,
                      "textColor": "#20263D",
                      "iconImageName": "incdOnboarding.help.clipped",
                      "iconTintColor": "#20263D",
                      "iconPosition": "left",
                      "iconPadding": 8,
                      "transform": {
                        "a": 1,
                        "b": 0,
                        "c": 0,
                        "d": 1,
                        "tx": 0,
                        "ty": 0
                      }
                      },
                      "highlighted": {
                      "animateStateChange": true,
                      "alpha": 1,
                      "backgroundColor": "#20263D",
                      "borderColor": "",
                      "borderWidth": 0,
                      "cornerRadius": 32,
                      "shadowColor": "#000000",
                      "shadowOffset": [0,5],
                      "shadowOpacity": 0.15,
                      "shadowRadius": 9,
                      "textColor": "#00B2FD",
                      "transform": {
                        "a": 1,
                        "b": 0,
                        "c": 0,
                        "d": 1,
                        "tx": 0,
                        "ty": 0
                      }
                      },
                      "disabled": {
                      "animateStateChange": true,
                      "alpha": 1,
                      "backgroundColor": "#E9E9EB",
                      "borderColor": "",
                      "borderWidth": 0,
                      "cornerRadius": 32,
                      "shadowColor": "#000000",
                      "shadowOffset": [0,5],
                      "shadowOpacity": 0,
                      "shadowRadius": 9,
                      "textColor": "#FFFFFF",
                      "transform": {
                        "a": 1,
                        "b": 0,
                        "c": 0,
                        "d": 1,
                        "tx": 0,
                        "ty": 0
                      }
                  }
                },
                "labels": {
                  "title": {
                    "textColor": "#20263D",
                    "kerning": 0
                  },
                  "secondaryTitle": {
                    "textColor": "#FFFFFF",
                    "kerning": 0
                  },
                  "subtitle": {
                    "textColor": "#20263D",
                    "kerning": 0
                  },
                  "secondarySubtitle": {
                    "textColor": "#FFFFFF",
                    "kerning": 0
                  },
                  "smallSubtitle": {
                    "textColor": "#20263D",
                    "kerning": 0
                  },
                  "info": {
                    "textColor": "#636670",
                    "kerning": 0
                  },
                  "secondaryInfo": {
                    "textColor": "#FFFFFF",
                    "kerning": 0
                  },
                  "body": {
                    "textColor": "#20263D",
                    "kerning": 0
                  },
                  "secondaryBody": {
                    "textColor": "#FFFFFF",
                    "kerning": 0
                  },
                  "code": {
                    "textColor": "#20263D",
                    "kerning": 16
                  }
                },
                "customComponents": {
                  "cameraFeedback": {
                    "alpha": 0.8,
                    "backgroundColor": "#000000",
                    "cornerRadius": 20,
                    "textBackgroundColor": "",
                    "textColor": "#FFFFFF"
                  },
                  "idCaptureHelp": {
                    "commonIssueLayoutOrientation": "horizontal"
                  },
                  "idSideLabel": {
                    "alpha": 1,
                    "backgroundColor": "#FFFFFF",
                    "borderColor": "",
                    "borderWidth": 0,
                    "cornerRadius": 5
                  }
                },
              })

IncodeSdk.setTheme({jsonTheme: jsonTheme})