Fortface SDK integration in your Android app
How does it work?
The purpose of our SDK is to capture the photo that will be sent to our Fortface API. It is independent of the application flow of the app it will integrate with. It has its own isolated Activity, which can be started at any time by an Engine. As soon as it has been processed, the tool closes automatically.
Our SDK does not communicate directly with the Fortface API, see below for the communication flow:

Below are the instructions for integrating our SDK, the process flow for correctly accessing our service and step-by-step instructions on how to build an Engine.
Installation
Requirement
1. Platform Configuration
Android
It is currently possible to use the Fortface SDK in applications that support Android 6 - SDK 24 as the minimum version. However, by doing so, the developer gives up important security features of the tool, thereby assuming risks of attacks during captures.
Kotlin
Minimum version: 1.7.20
Installation
1. Add access to the Maven repository to your project
First you need to configure access to the Maven repository in your project. The artifact is served via CDN, with HTTP header authentication. Include the following block in repositories (for example in the app module’s build.gradle / build.gradle.kts, or in settings.gradle / settings.gradle.kts if your project uses dependencyResolutionManagement).
- Groovy
- Kotlin
repositories {
maven {
url "https://cdn-fortface-sdk.fortface.com.br"
credentials(HttpHeaderCredentials) {
name = "X-Sdk"
value = "ACCOUNT_NAME"
}
authentication {
header(HttpHeaderAuthentication)
}
}
}
repositories {
maven {
url = uri("https://cdn-fortface-sdk.fortface.com.br")
credentials(HttpHeaderCredentials::class) {
name = "X-Sdk"
value = "ACCOUNT_NAME"
}
authentication {
create<HttpHeaderAuthentication>("header")
}
}
}
Replace ACCOUNT_NAME with the account identifier provided by our team.
Depending on your project configuration, you may need to declare the same repository in
settings.gradle/settings.gradle.kts(for example insidedependencyResolutionManagement { repositories { ... } }).
2. Configuring gradle
With the repository configured, you need to activate viewBinding and add the dependency to our SDK. Below you'll find the changes you need to add to your app's gradle:
- Groovy
- Kotlin
android {
...
buildFeatures {
viewBinding true
}
}
dependencies {
implementation (group: 'br.com.fortface', name: 'fortface', version:'1.20.0', ext: 'aar', classifier: 'release'){
transitive = true
}
}
android {
...
buildFeatures {
viewBinding = true
}
}
dependencies {
implementation("br.com.fortface:fortface:1.20.0:release@aar") {
isTransitive = true
}
}
Don't forget to synchronize your project with the gradles files after modification.
Não se esqueça de sincronizar o seu projeto com os arquivos gradles após alteração.
3. Include Proguard rules
Our SDK already has obfuscation and minification for security assurance; however, some classes from the SDK need to be kept without obfuscation to ensure your app functions correctly. Add the following rules to your proguard-rules.pro file:
-keep class br.com.fortface.sdk.** { *; }
Permission
1. Adjust AndroidManifest.xml
Our SDK uses the camera, so you need to configure the access permission in the manifest of your app. To do this, add the following lines to the file:
<uses-permission android:name="android.permission.CAMERA" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.camera.autofocus" />
<application
...
Our SDK also has a permission for location to collect geolocation coordinates of the device for reinforcement in antifraud mechanisms. If you want to collect the geolocation coordinates of the device, add the location permission to your app's manifest as well.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<application
...
2. Grant access to the camera
For your application to request permission to access the camera, add the following code to your activity:
Snippet Kotlin
- Kotlin
- Java
class YourActivity: AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
// ...
if (!allPermissionsGranted()) {
requestPermission()
}
}
private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
ContextCompat.checkSelfPermission(this.baseContext, it) == PackageManager.PERMISSION_GRANTED
}
private fun requestPermission() {
ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)
}
companion object {
const val REQUEST_CODE_PERMISSIONS = 10
val REQUIRED_PERMISSIONS = arrayOf(
Manifest.permission.CAMERA,
Manifest.permission.ACCESS_FINE_LOCATION, // Optional
Manifest.permission.ACCESS_COARSE_LOCATION // Optional
)
}
// ...
}
public class YourActivity extends AppCompatActivity {
private static final int REQUEST_CODE_PERMISSIONS = 10;
private static final String[] REQUIRED_PERMISSIONS = {Manifest.permission.CAMERA, Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION}; // ACCESS_FINE_LOCATION and ACCESS_COARSE_LOCATION are optional
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
// ...
if (!allPermissionsGranted()) {
requestPermission();
}
}
private boolean allPermissionsGranted() {
for (String permission : REQUIRED_PERMISSIONS) {
if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
return false;
}
}
return true;
}
private void requestPermission() {
ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS);
}
// ...
}
After this configuration, your application is ready to access our SDK.
Pre-initialization
Before starting the capture process, it is necessary to establish the integrity of the device to ensure secure communication with the Fortface API. It is therefore necessary to:
- import our SDK into your app;
- Instantiate
FortfaceSdk.
Establish device integrity
Start the SDK and get the deviceRequestInfo.
- Kotlin
- Java
import br.com.fortface.sdk.FortfaceSdk
val deviceRequestInfo = FortfaceSdk.start(appContext, false)
println(deviceRequestInfo)
// Q4ezAXfMdAdW1s0xdwCcg0Jzj9kAjuNwzNrWMip4ADAylFQAGCgBOHT7HJYkPkXUPmLZ3XtJYOgTi/WKh+o2Vstk2MGy4qRz4fcBpCu+raS1ghHa4DDmqUjbSMPd3Fdo2zrcw0sb81FDf/Tos2A5UaIqMhzurkm0aYgC/izKhu3H+RQXJBHjFVKUIq8WPVbC/ITKon2T703C6fgdQtcpknaxAvIN2/eDRxBrsSuS3fbIi1TOoGAIi/Ezwj0utZLYUwhnKImaabvvXFdsvVxp6rHLiq1uHqZbm4tfRWJw4mkk47JHVEfUIJMFjS1ORpqoN1dmZzPQHAo0CtPfYGa9OB8NGnmgRRbWHXWrXPoptaRY31yoaT+HGwBwB/pfL8gUxoVppOYBUfIsvSQoaIQ+6g==
import br.com.fortface.sdk.FortfaceSdk;
String deviceRequestInfo = FortfaceSdk.start(appContext, false);
System.out.println(deviceRequestInfo);
In FortfaceSdk, we will use the start method which has 2 parameters and returns 1 string:
contextparameter: represents the context of your application.- Parameter
isDebugMode: represents a boolean that enables or disables debug mode. Default value isfalse.
- Use
trueto enable debug mode; - Use
falsein production, so that the integrity of the device is checked and, if it is not suitable for transactions, an exception of typeFortfaceExceptionwill be thrown with the message There is something wrong!.
- Return stored in
deviceRequestInfo: string used to validate the integrity of the device connected to our SDK. A newdeviceRequestInfois generated each time the method is called (in the code above is an example).
With deviceRequestInfo in hand, you can now make a handshake call between your back-end and API Fortface.
handshakeis an important security measure for establishing reliable communication between your back-end and API Fortface, making it possible to verify device authenticity, share sensitive information (encryption keys and sessions) and establish a secure channel for data exchange.
A successful `handshake' ensures that the device is intact and your app has the information it needs to proceed.
Capture
Knowing that the integrity of the device has been established, let's understand how to start the session and use the IFortfaceEngine interface to perform the capture.
Establishing the device session
Implement a class that extends IFortfaceEngine.
- Kotlin
- Java
import br.com.fortface.sdk.FortfaceManagerSession
import br.com.fortface.sdk.IFortfaceEngine
import br.com.fortface.sdk.utils.SessionDetails
class YourEngine(appContext: Context, sessionKey: String, sessionId: String, private val yourViewModel: ViewModel) : IFortfaceEngine {
init {
val sessionDetails = SessionDetails(
getGeolocation = true // 👈 Optional: define if the SDK should request location permission and collect coordinates for antifraud reinforcement.
)
FortfaceManagerSession.startSessionFaceEngine(
appContext,
this,
sessionId,
sessionKey,
sessionDetails // can be omitted if you don't need the additional controls of usability to the session
)
}
}
import br.com.fortface.sdk.FortfaceManagerSession;
import br.com.fortface.sdk.IFortfaceEngine;
public class YourEngine implements IFortfaceEngine {
private final String sessionKey;
private final String sessionId;
private final ViewModel yourViewModel;
public YourEngine(Context appContext, String sessionKey, String sessionId, ViewModel yourViewModel) {
this.sessionKey = sessionKey;
this.sessionId = sessionId;
this.yourViewModel = yourViewModel;
// 👇 Optional: define if the SDK should request location permission and collect coordinates for antifraud reinforcement.
SessionDetails sessionDetails = new SessionDetails(true);
FortfaceManagerSession.startSessionEngine(
appContext,
this,
sessionId,
sessionKey,
sessionDetails // can be omitted if you don't need the additional controls of usability to the session
);
}
}
In this class, initialize FortfaceManagerSession and its startSessionEngine method which has 5 parameters:
context: represents the context of your application.engine: represents your Engine class which implements theIFortfaceEngineinterface of our SDK. This will be explained below, in the session Creating an Engine.sessionId: session id, generated in the Fortface API.sessionKey: encryption key generated in API Fortface.sessionDetails: optional object that allows adding other controls of usability to the session.getGeolocation: define if the SDK should request location permission and collect coordinates for antifraud reinforcement.
By initializing the FortfaceManagerSession using the parameters provided, you correctly configure the secure communication session and ensure that the data transmitted between the application and the server is properly encrypted and protected.
Mock data for example:
AppContext: Context of your application
Engine: Reference of your Engine that implements the
IFortfaceEngine.
SessionId: nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2k
SessionKey: -----BEGIN PUBLIC KEY----- \nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2k+o81Oiti4TDezZYD8Q\nzj2RjO5f/YQHGmC1v7CWC4AJpD9+FOXBBO1pImaSg1gb8kOobRFGWbVdiHm35+PF\nTJceH31r+jKnvfc1TshsQVGtYLm7x5E/GFcjpGx9LdSxiXC6cHdCJf3o02/lytBa\nu8NCoH9FpPjyKrdGdSRb2haviAuEV4N1UBd5uZIsacVqZj52i1z+I94gLVKBZ/UV\npaxjLPWWngmaxbyKE0sEbt9JGleiCb2P1kZA9sU4L4Po7WBNk0+QOsvW9QjvS1+6\ntcZwwIDll2LyUceiFgxF6GkuFcHlBZDDtzymDDC2IYrf9/FNBOPeV1JHXON8T6DY\nAwIDAQAB\n- ----END PUBLIC KEY-----\n
The string that represents the sessionKey contains special characters (such as the line break \n) that must be preserved exactly as received from the Fortface API. Be careful with any accidental manipulation that may occur in:
- Form inputs
- Logs and monitoring systems
- String processing in your backend
- Transfers between services
- Database storage
Any change to these characters may cause the key validation to fail. Make sure the key is passed to the SDK exactly as received from the Fortface API.
For local frontend development only, you may reuse the same valid sessionKey as a mock as many times as necessary. The single-use restriction applies only in the context of backend development, when the Fortface API validates the key.
Understanding the code snippet:
- The constructor method of the class will call
FortfaceManagerSession.start. - The session is created and the camera is rendered on the screen to capture the user's face.
Creating an Engine
Through the Engine you can access the information processed by our SDK. To create an Engine, the class must implement the IFortfaceEngine interface, so it is necessary to implement the finishedSessionEngine method. It is in this method that the data processed by the SDK will be received, which is a package with an action and the captured image data.
Below you can see the complete implementation of a capture, for example, the YourEngine class which implements the IFortfaceEngine interface, containing the initialization of the startSessionEngine session and the handling of the SessionEngineResult callback.
**Snippet Kotlin
- Kotlin
- Java
import br.com.fortface.sdk.Action
import br.com.fortface.sdk.SessionEngineResult
import br.com.fortface.sdk.FortfaceManagerSession
import br.com.fortface.sdk.IFortfaceEngine
class YourEngine(appContext: Context, sessionKey: String, sessionId: String, private val yourViewModel: ViewModel) : IFortfaceEngine {
init {
FortfaceManagerSession.startSessionEngine(appContext, this, sessionId, sessionKey)
}
override fun finishedSessionEngine(sessionEngineResult: SessionEngineResult) {
when (sessionEngineResult.action) {
Action.Capture -> yourViewModel.captured(sessionEngineResult) // Here the flow ends and this is the data to send
Action.Cancel -> yourViewModel.canceled() // Here the user has canceled the capture and you must continue with your cancellation flow
Action.Timeout -> yourViewModel.timeout() // Here the capture was canceled because it ran out of time. You must follow the timeout flow.
Action.Error -> yourViewModel.erro() // Here the capture was canceled because an error occurred. You should handle it more appropriately according to the returned errorCode.
else -> {}
}
}
}
import br.com.fortface.sdk.SessionEngineResult;
import br.com.fortface.sdk.FortfaceManagerSession;
import br.com.fortface.sdk.IFortfaceEngine;
public class YourEngine implements IFortfaceEngine {
private final Context appContext;
private final String sessionKey;
private final String sessionId;
private final ViewModel yourViewModel;
public YourEngine(Context appContext, String sessionKey, String sessionId,
, ViewModel yourViewModel) {
this.sessionKey = sessionKey;
this.sessionId = sessionId;
this.yourViewModel = yourViewModel;
FortfaceManagerSession.startSessionEngine(appContext, this, sessionId, sessionKey);
}
@Override
public void finishedSessionEngine(SessionEngineResult sessionEngineResult) {
switch (sessionEngineResult.getAction()) {
case Capture:
yourViewModel.captured(sessionEngineResult); // Here ends the flow and this is the data to send
break;
case Cancel:
yourViewModel.canceled(); // Here the user has canceled the capture and you must continue with your cancellation flow
break;
case Timeout:
yourViewModel.timeout(); // Here the capture has been canceled because it has run out of time. You should follow the timeout flow
break;
case Error:
yourViewModel.erro() // The capture was canceled because an error occurred. You should handle it more appropriately based on the returned errorCode.
break;
default:
break;
}
}
}
Note that the finishedSessionEngine method is a callback that has a data type SessionEngineResult, the callback has two pieces of information:
-
action: represents an enumerator containing:Capture: callback of the capture made by the userCancel: callback of the capture canceled by the userTimeout: callback of the capture with the timeout reached by the user- This
actionrepresents the time that the SDK is open, whether it is capturing or not. When it runs out, the SDK is closed and the camera is closed; - The default time is 30 seconds;
- If you want to change it, check the customization session.
- This
Error: capture callback triggered when an error occurs during the process -Thisactionrepresents an error generated during the capture.
-
getData: represents the encrypted capture data and is in JSONObject format. JSON is represented by the following structure:
{
key: String,
data: String,
imgData: String,
imgPreview: String
}
sessionDetails: is a data type that contains anerrorCodefield.errorCode: represents a code that may occur during the capture and/or upload process. The possible values are:DocumentNotFound: code returned when the selected file (PDF/Image) cannot be found.FileSizeTooBig: code returned when the selected file (PDF/Image) exceeds the allowed limit of4MB.FileCorrupted: code returned when the selected file (PDF/Image) is corrupted.InvalidSessionKey: code returned when the sessionKey provided to the SDK is invalid.CameraAccessPermissionError: code returned when the user does not grant camera access to the application.ImageClosed: code returned when the capture process attempts to handle a frame whose image is unavailable.OutOfMemory: code returned when the device does not have enough available memory for the SDK to continue processing.
So, as the example above shows, you can direct each action to its own implementation in your application. In addition, once the information is obtained from the getData method, your application can transport it in the most convenient way to your backend and then to the Fortface API.
It's important to note that in our SDK's API there will be enroll and identify flows, so you are free to architect Engines that correspond to each of these flows, or to architect a generic Engine, or any other desired solution.
Using our SDK
In the example of using the SDK, we will use MVVM architecture. With this, we have the view model:
- Kotlin
- Java
class YourViewModel: ViewModel() {
fun caputed(sessionEngineResult: SessionEngineResult) {
//Implement what to do with the captured data
}
fun canceled() {
//Implementation of SDK cancellation
}
fun timeout() {
//Implement SDK timeout
}
fun error() {
//Implement SDK error
}
}
public class YourViewModel extends ViewModel {
public void captured(SessionEngineResult sessionEngineResult) {
//Implementation of what to do with the captured data
}
public void canceled(){
//Implementation of SDK cancellation
}
public void timeout() {
//Implement SDK timeout
}
public void error() {
//Implement SDK error
}
}
The SDK is free to implement any project structure. In this documentation we use the architecture standard used in the market.
Below is a code example of the flow that must be implemented in your app to access our SDK:
- Kotlin
- Java
import br.com.fortface.sdk.FortfaceSdk
import androidx.activity.viewModels
//...
class YourActivity : AppCompatActivity() {
val yourViewModel: YourViewModel by viewModel()
//...
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
if (!allPermissionsGranted()) {
requestPermission()
}
val button = findViewById<Button>(R.id.button)
button.setOnClickListener {
startEngine()
}
}
fun startEngine() {
val deviceRequestInfo = FortfaceSdk.start(this, false)
// Here you send it to the Fortface API handshake via your backend
// ...
// With the response you'll get the sessionKey and sessionId
val sessionKey = ''; // Fortface API response
val sessionId = ''; // Fortface API response
YourEngine(this, sessionKey, sessionId, yourViewModel)
}
}
import br.com.fortface.sdk.FortfaceSdk;
import androidx.lifecycle.ViewModelProvider;
//...
public class YourActivity extends AppCompatActivity {
YourViewModel yourViewModel;
//...
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
yourViewModel = new ViewModelProvider(this).get(YourViewModel.class);
if (!allPermissionsGranted()) {
requestPermission();
}
Button button = findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
startEngine();
}
});
// ...
}
private void startEngine() {
String deviceRequestInfo = FortfaceSdk.start(this, false);
// Here you send it to the Fortface API handshake via your backend
// ...
// With the response you'll get the sessionKey and sessionId
String sessionKey = ''; // Resposta da API Fortface
String sessionId = ''; // Resposta da API Fortface
new YourEngine(this, sessionKey, sessionId, yourViewModel);
}
}
Versioning
To find out which version of our SDK is being used, just call the function FortfaceSDK.getVersion() which will return a String with its value. Example:
String sdkVersion = FortfaceSDK.getVersion()
System.out.println(sdkVersion);
// 1.17.0
Full screen mode
By default, our SDK is displayed in full screen mode in portrait orientation. This setting is valid for all supported devices. However, on tablets, it is possible to set the orientation to horizontal (landscape) or automatic, allowing the SDK to follow the orientation of the device in use.
If the SDK is set to an orientation other than portrait and run on a smartphone, it will automatically be displayed in portrait, ignoring the customization made. The possible configuration values are:
- Kotlin
- Java
customizer.screenOrientation = ScreenOrientation.Automatic
customizer.screenOrientation = ScreenOrientation.Landscape
customizer.screenOrientation = ScreenOrientation.Portrait
customizer.screenMode = ScreenMode.FullScreen
customizer.setScreenOrientation(ScreenOrientation.Automatic);
customizer.setScreenOrientation(ScreenOrientation.Landscape);
customizer.setScreenOrientation(ScreenOrientation.Portrait);
customizer.setScreenMode(ScreenMode.FullScreen);
Modal Mode
We offer the option of customizing the display of the SDK's capture stream in a modal that overlays the client application's screen. This functionality is only available for tablets. When configured and run on smartphones, the SDK will adopt full-screen display behavior in portrait orientation. In modal mode, you can customize the background color (overlay) and its opacity.
- Kotlin
- Java
customizer.screenMode = ScreenMode.Modal
customizer.modalBackground.setOverlayColor(“#5FC213”)
customizer.modalBackground.overlayOpacity = 0.4f
customizer.setScreenMode(ScreenMode.Modal);
customizer.getModalBackground().setOverlayColor(“#5FC213”);
customizer.getModalBackground().setoverlayOpacity(0.4f);
Cancel callback and timeout
When an attempt to capture the user's face is not completed successfully, for example when the user cancels the capture or when the capture does not take place during the given time, it is important that the event is sent to the backend in order to have correct metrics of the success or failure of the captures.
To allow us to have the data of the canceled or timeout capture, our SDK has callbacks in the cancel capture action and in the capture timeout action.
The SessionEngineResult received in the finishedSessionEngine function is an object that has 2 properties: data and action (action performed in the SDK). Previously, the date field was only filled in at the end of the face capture.
As seen earlier in the Capture topic, the data contains encrypted data and can be converted into JSON. However, unlike the capture, in this scenario after conversion to JSON, we will only have the following fields:
{
key: String,
data: String
}
Reminder: The key and data keys are generated by the SDK, sent to your back-end and then to the Fortface API.
Implementation example
-
we have identified in the SDK that there has been a capture cancellation.
-
We create the encrypted object.
-
Finish the SDK and send the generated payload and the action taken.
-
In the implementation app, within the class that extends the
IFortfaceEngine, it is detected that an action has taken place.
- Kotlin
import br.com.fortface.sdk.Action
import br.com.fortface.sdk.SessionEngineResult
import br.com.fortface.sdk.FortfaceManagerSession
import br.com.fortface.sdk.IFortfaceEngine
class YourEngine(appContext: Context, sessionKey: String, sessionId: String, private val yourViewModel: ViewModel) : IFortfaceEngine {
...
override fun finishedSessionEngine(sessionEngineResult: SessionEngineResult) {
when (sessionEngineResult.action) {
Action.Capture -> yourViewModel.captured(sessionEngineResult)
// when the cancel action is detected, the canceled function is called
// which receives the date generated in the SDK.
Action.Cancel -> yourViewModel.canceled(sessionEngineResult)
Action.Timeout -> yourViewModel.timeout(sessionEngineResult)
else -> {}
}
}
}
- Inside your ViewModel, the
canceled()function is called.
- Kotlin
class YourViewModel: ViewModel() {
...
fun canceled() {
// trigger that we receive the cancel action
cancelAction.postValue(true)
// creation of the cancellation payload in Metric format
createPayload(sessionEngineResult)
createPayload(sessionEngineResult)
}
...
private fun createPayload(sessionEngineResult: SessionEngineResult) {
val encryptedPayload = sessionEngineResult.getData().toString()
if (encryptedPayload != "null") {
// parse the JSON to the SDKData object (example below)
// in this case the imgData field will be null
val sdkData = Gson().fromJson(encryptedPayload, SDKData::class.java)
// trigger that we receive a metric and send the Metrics
sessionEngineResultValue.postValue(Metrics(sdkData))
}
}
}
- Metrics object
- Kotlin
@Keep
data class Metrics(
@SerializedName(“sdkData”)
var sdkData: SDKData
)
- SDKData object
- Kotlin
@Keep
data class SDKData(
@SerializedName(“key”)
val key: String,
@SerializedName(“data”)
val data: String,
@SerializedName(“imgData”)
val imgData: String
)
- After triggering the receipt of the metric, Metrics is sent to the API
- Kotlin
class YourFragment : Fragment() {
...
// observer sees that there is a new metric to send
// sends data to the metrics API
viewModel.sessionEngineResultValue.observe(viewLifecycleOwner) {
context?.let { context -> viewModel.sendMetricsToServer(context, it) }
}
Summary
- Check camera access permission
- Capture deviceRequestInfo
- Handshake API Fortface (via your backend)
- Start an Engine
- Receive the data in the Engine callback
- Send to API Fortface (via your backend)
- Receive response from API Fortface and proceed with your business rule