Video Verification with Gesture
Introduction
Video verification is an iframe based product allows secure end-customer onboarding digitally. It helps you capture live randomized video of your end-user and match against a predefined ID proof/photograph. The system has advanced video fraud detection capabilities which eliminate identity theft in user onboarding process. Thus ensuring secure yet simple customer onboardings. If you have a web based application (be it mobile web or desktop web) you can access this through an iframe. In your mobile application you can use webview. If you have ever integrated iframe based payment gateways, you would find this to be very similar: Bet you already knew this, so let's get to the meat of how to get this done.
Gestures
From the availaible gestures you have to give gestureSequenceLength minimum 3 to maximum 7.
Following is the list of gestures:
- Blink
- Smile
- Yawn
- Left
- Right
The system will arrange these gestures in randomized way so that every time user will be presented to a new sequence of gesture. In this way user can't forge the sequence.
Product Flow
- User initiates a video verification.
- Signzy iframe takes over and asks a user to perform randomized Sequence of gesture, at end ask user to speak aloud the number presented to them. After the process gets completed, whole recorded video gets processed by AI server.
- This video data now passes onto the backend fraud detection engine. Final output of the product gives 2 different scores and two boolean values which achieves the following.
- Predict if the user present in the video is same as the one in ID proof.
- Ensure that the a live person was present infront of the camera. Static photo risk and Pre-recorded video risk scores indicate chances of fraud on this front.
While integrating it in iframe allow the microphone and camera in attribute of iframe tag. allow="camera; microphone;"
After integration you can listen for an event named videoUploadingDone in your parent window to know exactly when the whole video verification process has completed. Below is the code for the listening of this event.
window.addEventListener('message', function(event) {
if (event.data.message == 'videoUploadingDone') {
// do here what you want to do after video verification process gets completed
}
}, false); Integration Flow
Logging in
You would have understood logging in by now. In case you are only integrating video verification you can understand logging in from Authentication section.
Create URL
Once you are logged in, you need to initiate video verification session by creating a url in the following manner. Note: Before initiating a video verification session you will also need to pass a matchUrl which can be an array of ID/ face images. You can use your own filesystem or use our system as explained in our file exchange section. please note that rotated images are not supported.
Endpoint Details
POST https://signzy.tech/api/v2/patrons/...patronID.../videoiframesPOST https://preproduction.signzy.tech/api/v2/patrons/..your-patron-id../videoiframesRequest Body Parameters
Following is the JSON format of the request body parameter with the description of all key-value pairs:
{
"task" : "gestureUrl",
"essentials" : {
"matchImage" : ["Images Array maximum two images are allowed"],
"validGestures": [ ..validGestures...],
"gestureSequenceLength": "..total no of gesture..",
"languageCode":"...en/hi/es...(default=en)"
"callbackUrl" : "...URL on which response to be pushed once the Video Verification is Completed...",
"redirectUrl": "....A valid URL...",
customizations: {
"otpRequired": "...true/false...(default=false)",
"--main-bg-color": "...main background color...",
"--button-bg-color": "...button background color...",
"--main-heading": "...main Heading color...",
"logoUrl": "...url of the logo image...",
"hideSecuredBySignzyLogo": "...true/false (boolean) ...",
"hideTopLogo": "....true/false (boolean)...",
"enableVPNCheck": "....true/false (boolean)...",
"isThankYouRequired": "....true/false (boolean)...",
"logoAlignment": "",
"subTitleAlignment": "",
"titleAlignment": "",
"loader": {
"bgColor": "...valid hex color...",
"txtColor": "......valid hex color......",
"barColor": "......valid hex color......",
},
"subTitleColor": "...valid hex color...",
"titleColor": "...valid hex color...",
"backgroundColor": "...valid hex color...",
"instructionColor": "...valid hex color...",
"progressBar": {
"backgroundColor": "...valid hex color...",
"innerBackgroundColor": "...valid hex color..."
"fillColor": "...valid hex color..."
},
"instructions": {
"left":"...(optional field for custom instruction for left gesture)..."
"right":"...(optional field for custom instrcution for right gesture)..."
"blink":"...(optional field for custom instrcution for blink gesture)..."
"smile":"...(optional field for custom instrcution for smile gesture)..."
"yawn":"...(optional field for custom instrcution for yawn gesture)..."
}
}
}
}Request Headers
Name | Required/Optional | Description |
|---|---|---|
Authorization | Required | access token returned as id field of login request |
Content-Type | Required | application/json |
Code Samples
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://signzy.tech/api/v2/patrons/....patronid.../videoiframes"
method := "POST"
payload := strings.NewReader(`{"task":"gestureUrl","essentials":{"matchImage":["...matchImageUrl..."],"customVideoRecordTime":"..number between 5-30...(optional)","callbackUrl":"...callbackUrl...","gestureSequenceLength":"...gestureSequenceLength..","validGestures":["...validGestures..."],"customizations":{"isThankYouRequired":"...true/false..."}}}`)
client := &http.Client {
}
req, err := http.NewRequest(method, url, payload)
if err != nil {
fmt.Println(err)
return
}
req.Header.Add("Accept", "*/*")
req.Header.Add("Accept-Language", "en-US,en;q=0.8")
req.Header.Add("Authorization", "<Access-Token>")
req.Header.Add("content-type", "application/json")
res, err := client.Do(req)
if err != nil {
fmt.Println(err)
return
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(body))
}Response Body Parameters
Parameter | Data type | Description |
|---|---|---|
result | Object | Object storing the output parameters |
result.token | String | Represents the token associated with the video. |
result.videoUrl | String | Specifies the URL of the video to be loaded in an iframe. |
{
"result": {
"token": "..token...",
"videoUrl": "..URL to be loaded in iframe..."
}
}Load videoUrl
Once you receive the videoUrl:
- In case of webapp product,load the URL in the iframe
- In case of mobile APP, WebView is not supported, but you can use chrome custom tab.
To use this just import following in your app.gradle file
implementation 'saschpe.android:customtabs:2.0.0'and instead of Webview, use:
CustomTabsIntent customTabsIntent = new CustomTabsIntent.Builder()
.addDefaultShareMenuItem()
.setToolbarColor(this.getResources().getColor(R.color.colorPrimary))
.setShowTitle(true)
.build();
// This is optional but recommended
CustomTabsHelper.addKeepAliveExtra(this, customTabsIntent.intent);
// This is where the magic happens...
CustomTabsHelper.openCustomTab(this, customTabsIntent,
Uri.parse("...video url that u have recieved..."),
new WebViewFallback());The session will now record the video of the end- customer.
Getting the results
If Callback URL is provided then whole response/error in JSON format will be posted(POST METHOD) is posted to that URL.
Endpoint Details
POST https://signzy.tech/api/v2/patrons/...patronID.../videoiframesPOST https://preproduction.signzy.tech/api/v2/patrons/..your-patron-id../videoiframesRequest Body Parameters
Parameter | Data Type | Description | Required |
|---|---|---|---|
task | String | Specifies the type of task to be performed (e.g., getData). | Yes |
essentials.token | String | Represents the token received in the Unique URL Generation Request. | Yes |
essentials.patronId | String | Unique ID for each Patron. Example : Will be a alphanumeric value of 24 length such as 5a12eaf09fa3e67936b43c52 | Yes |
{
"task": "getData",
"essentials": {
"token": "..token received in the Unique URL Generation Request...",
"patronId": "..patron ID is returned as userId parameter of login request..."
}
}Request Body Headers
Name | Required/Optional | Description |
|---|---|---|
Authorization | Required | access token returned as id field of login request |
Content-Type | Required | application/json |
Code Samples
package main
import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)
func main() {
url := "https://signzy.tech/api/v2/patrons/....patronid.../videoiframes"
method := "POST"
payload := strings.NewReader(`{"task":"getData","essentials":{"token":"...token..","patronId":"...patronId.."}}`)
client := &http.Client {
}
req, err := http.NewRequest(method, url, payload)
if err != nil {
fmt.Println(err)
return
}
req.Header.Add("Accept", "*/*")
req.Header.Add("Accept-Language", "en-US,en;q=0.8")
req.Header.Add("Authorization", "<Access-Token>")
req.Header.Add("content-type", "application/json")
res, err := client.Do(req)
if err != nil {
fmt.Println(err)
return
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(body))
}Response Body
{
"result": {
"token": "...token..",
"videoUrl": "..URL loaded in iframe...",
"callbackUrl": "...callback url....",
"gestureSequenceLength": "..total no of gestures...",
"isUsed": 1,
"videoVerification": {
"videoFaceMatch": [
{
"videoImages": [
"...images extracted from the video... "
],
"finalMatchImage": "matchImage used for the the video",
"matchStatistics": {
"coVariance": "..coVariance..",
"matchPercentage": "..average percentage match of the images.."
}
}
],
"audioMatch": {
"matchAudioScore": "...audio match with the random text shown on the screen.."
},
//This blocks has value when more than one match Images are passed
"matchImageFaceMatch": {
"verified": "true/false",
"message": "...Verification result in text..",
"matchPercentage": "..percentage match of the images.."
},
"videoForensics": {
"staticRisk": "..whether a static photo is used to record the video..",
"prerecordedRisk": "..whether a precorded video is used to record the video..",
"videoLandMarks": "..url of face tracked video",
"faceLandMarks": [
"..url of face demarcated image.."
]
},
"video": "... video url ....",
"videoStartTime": 1579094778212,
"gestureSequence": [
"2"
],
"gestureFaceTimeStamps": [
[]
]
}
}
}Parameter Description
Parameters | Description | Possible Values |
|---|---|---|
TASK | Type of Transaction performed in Signzy System. | url,getData(Compulsory) |
Patron ID | Unique ID for each Patron. Example : Will be a alphanumeric value of 24 length such as 5a12eaf09fa3e67936b43c52 | Compulsory |
Token | Unique ID for each Video Verification Session Transaction. Example : Will be a alphanumeric value of 20 length such as AfZwmorpcBp17nYZkIJY | Compulsory |
MatchImage | The ID/Face images of the individual which is used to match with face in the video. | Compulsory |
Video Url | The unique URL generated in response of Create URL request which should be loaded in the iframe. | Compulsory |
Callback URL | Callback url is to post results to some other url for the particular request. Example : https://www.w3schools.com/ | Optional |
Customizations | A customization object with the fields --main-heading as a Hex color (#ABCDEF) -button-bg-color as a Hex Color (#ABCDEF) -button-bg-color as a Hex Color (#ABCDEF) logoUrl (a direct url to a logo) hideTopLogo (boolean) enableVPNCheck (boolean) isThankYouRequired (boolean) hideSecuredBySignzyLogo (boolean). logoAlignment: left | center | right subTitleAlignment left | center | right titleAlignment left | center | right loader.bgColor as a valid HEX color loader.txtColor as a valid HEX color loader.barColor as a valid HEX color subTitleColor as a valid HEX color titleColor as a valid HEX color backgroundColor as a valid HEX color instructionColor as a valid HEX color progressBar.backgroundColor as a valid HEX color progressBar.innerBackgroundColor as a valid HEX color progressBar.fillColor as a valid HEX color | Optional |
Getting help
Please feel free to contact us if you have any questions, require clarification, or have ideas for how to make the documents or any of our services better.
You can reach out to us at [email protected].